Ruby之父父松本行弘说过:“Ruby是为了让程序员快乐而设计的语言。” 快乐来自于自由和优雅的表达,所以他为Ruby设计了非常多的语法糖,初见Ruby让人惊叹于它的简洁和优雅,让我们一起领略一下Ruby的黑魔法吧。
输出方法 Ruby提供了多种输出方法,每种都有自己的特色,选对工具很重要!
print方法:不自动换行
输出:hi,ruby!
puts方法:自动换行
输出:hi,
ruby!
p方法:区分数值与字符串,\n、\t输出时不会转义
输出:1
"1"
p方法在调试时特别好用,它会调用对象的inspect方法,能清楚地看到对象的真实类型!
pp方法:输出格式化文本
1 2 3 4 5 6 require "pp" v = [{ word: "Hi" , name: "Mark" }] pp v
输出:[{:word=>"Hi",
:name=>"Mark"}] #sublime实际输出是一行!!
pp方法处理复杂的嵌套结构时简直是神器,比p方法更易读!
中文编码 首行代码添加注释#encoding:编码方式
在Ruby 2.0之后,UTF-8成为默认编码,但加上这行注释是个好习惯,能避免很多莫名其妙的编码问题!
字符串插值 使用#{变量}的方式将变量输出到字符串
1 2 3 4 language = "Ruby" print "我在学习#{language} !"
字符串插值可以执行任意Ruby代码,不仅仅是变量:
1 2 3 4 5 puts "1 + 1 = #{1 + 1 } " puts "当前时间:#{Time .now} "
注意:只有双引号字符串支持插值,单引号不行!这是Ruby的一个小陷阱。
times方法 数字也是对象,可以直接调用方法!这就是Ruby的魅力!
1 2 3 4 5 6 7 8 def func_say () puts "重要的话说三遍!" end 3 .times do |i | puts "第#{i+1 } 遍" func_say() end
输出:第1遍
重要的话说三遍!
第2遍
重要的话说三遍!
第3遍
重要的话说三遍!
times方法还可以用更简洁的大括号语法:
1 2 5 .times { |i | puts "#{i} " }
类似的还有upto和downto方法:
1 2 3 4 5 1 .upto(3 ) { |i | puts "向上数:#{i} " }3 .downto(1 ) { |i | puts "向下数:#{i} " }
符号(Symbol) 在字符串前加:符号是Ruby中独特的数据类型
符号和字符串看起来相似,但本质不同:符号是不可变的,相同的符号在内存中只有一份拷贝,而字符串每次创建都会分配新内存。这使得符号在用作hash的键时性能更好!
1 2 3 4 5 6 7 p "hello" .object_id p "hello" .object_id p :hello .object_id p :hello .object_id
在Rails中,符号随处可见,是Ruby的标志性特性之一!
正则匹配 /模式/ =~ 字符串,/模式/i =~ 字符串(加i表示不区分大小写)
Ruby的正则表达式非常强大,支持各种花式玩法:
1 2 3 4 5 6 7 8 9 10 11 12 p /ruby/i =~ "Hi,RUBY!" result = "Email: mark@example.com" .match(/(\w+)@(\w+)\.(\w+)/ ) p result[0 ] p result[1 ] p result[2 ] text = "Phone: 123-456-7890" p text.gsub(/\d/ , "*" )
ARGV ARGV读取命令行参数
1 2 3 4 5 6 num_one = ARGV [0 ].to_i num_two = ARGV [1 ].to_i puts "#{num_one+num_two} "
ARGV是一个数组,可以用各种数组方法操作它:
1 2 3 4 5 6 7 8 9 if ARGV .empty? puts "请提供参数!" exit end ARGV .each_with_index do |arg, index | puts "参数#{index} : #{arg} " end
多重赋值 Ruby的多重赋值简直是语法糖中的战斗机!
变量前加*,表示将未分配的值封装成数组赋值给该变量
1 2 3 4 5 6 7 a,*b = 1 ,2 ,3 p a p b
交换变量的值
1 2 3 4 5 a = 10 b = 20 a,b = b,a puts "a=#{a} ,b=#{b} "
不需要临时变量,一行搞定!这在其他语言里可做不到。
数组赋值
1 2 3 4 arr = [10 ,20 ] a,b = arr puts "a=#{a} ,b=#{b} "
嵌套数组赋值
1 2 3 4 arr = [10 ,[20 ,30 ]] a,(b,c) = arr puts "a=#{a} ,b=#{b} ,c=#{c} "
忽略不需要的值
1 2 3 4 5 6 7 first, *, last = [1 , 2 , 3 , 4 , 5 ] puts "首尾:#{first} , #{last} " name, _, age = ["Mark" , "中间不重要" , 25 ] puts "#{name} 今年#{age} 岁"
范围(Range) Ruby的范围操作符太优雅了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (1 ..5 ).each { |i | print i } (1 ...5 ).each { |i | print i } arr = [10 , 20 , 30 , 40 , 50 ] p arr[1 ..3 ] p arr[1 ...3 ] p ('a' ..'e' ).to_a
后置条件 Ruby允许把if/unless放在语句后面,读起来像英语!
1 2 3 4 5 6 7 8 9 puts "太热了!" if temperature > 30 puts "该睡觉了" if Time .now.hour > 22 puts "天气不错" unless raining user.save! if user.valid? return nil unless user
安全导航操作符(&.) Ruby 2.3引入的神器,再也不怕nil错误了!
1 2 3 4 5 6 7 8 9 10 if user && user.profile && user.profile.avatar avatar = user.profile.avatar end avatar = user&.profile&.avatar p nil &.upcase
默认值操作符(||=) 这个操作符太常用了,堪称Ruby的标志性语法!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 count | |= 0 count += 1 count = count | | 0 @users | |= User .all hash = {} hash[:key ] | |= [] hash[:key ] << "value"
方法定义的灵活性 方法名可以带问号或感叹号,这是Ruby的命名约定!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def valid? true end def save! end def greet (name, age: 18 , city: "北京" ) puts "#{name} , #{age} 岁, 来自#{city} " end greet("Mark" ) greet("Mark" , age: 25 , city: "上海" ) puts "Hello"
块(Block)、Proc和Lambda Ruby的闭包三剑客,各有千秋!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [1 ,2 ,3 ].each { |n | puts n } my_proc = Proc .new { |n | puts n * 2 } my_proc.call(5 ) my_lambda = ->(n) { n * 2 } p my_lambda.call(5 )
tap方法 tap方法简直是调试和链式调用的神器!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 result = [1 ,2 ,3 ].map { |n | n * 2 } p result result = result.select { |n | n > 2 } p result [1 ,2 ,3 ] .map { |n | n * 2 } .tap { |arr | p "映射后:#{arr} " } .select { |n | n > 2 } .tap { |arr | p "过滤后:#{arr} " } user = User .new.tap do |u | u.name = "Mark" u.age = 25 end
case when的魔法 Ruby的case语句比其他语言强大得多!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 grade = 'B' case gradewhen 'A' puts "优秀" when 'B' puts "良好" else puts "加油" end case daywhen 'Monday' , 'Tuesday' , 'Wednesday' puts "工作日前半周" when 'Thursday' , 'Friday' puts "工作日后半周" end case scorewhen 90 ..100 puts "A" when 80 ...90 puts "B" when 60 ...80 puts "C" end case inputwhen /^\d+$/ puts "纯数字" when /^[a-z]+$/ i puts "纯字母" end case objwhen String puts "这是字符串" when Array puts "这是数组" end
猴子补丁(Monkey Patching) Ruby允许你随意修改已有的类,这就是”开放类”的威力!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class String def shout self .upcase + "!!!" end end p "hello" .shout class Integer def seconds self end def minutes self * 60 end def hours self * 60 * 60 end end p 5 .minutes p 2 .hours
这个特性超级强大但也很危险,用不好会导致难以调试的bug。在生产环境要谨慎使用!
method_missing Ruby的终极黑魔法:拦截不存在的方法调用!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class DynamicMethod def method_missing (method_name, *args ) puts "你调用了不存在的方法:#{method_name} " puts "参数是:#{args.inspect} " end end obj = DynamicMethod .new obj.hello("world" )
行内rescue 异常处理也可以写成一行!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 begin result = 10 / 0 rescue result = nil end result = 10 / 0 rescue nil value = some_risky_method rescue "默认值" content = File .read("config.txt" ) rescue ""
其他有趣的语法糖 无限循环
1 2 3 4 loop do puts "永远执行" break if condition end
until循环
1 2 3 4 5 i = 0 until i > 5 puts i i += 1 end
数组和哈希的花式创建
1 2 3 4 5 6 7 8 9 10 11 12 languages = %w[Ruby Python JavaScript] p languages symbols = %i[foo bar baz] p symbols hash1 = { :name => "Mark" , :age => 25 } hash2 = { name: "Mark" , age: 25 } hash3 = Hash [name: "Mark" , age: 25 ]
双星号( )操作符**
1 2 3 4 5 6 7 8 9 10 11 12 13 def method (name: , **others ) p name p others end method(name: "Mark" , age: 25 , city: "北京" ) params = { name: "Mark" , age: 25 } method(**params)
BEGIN和END
1 2 3 4 5 6 7 8 9 END { puts "程序结束时执行" }BEGIN { puts "程序开始前执行" }puts "主程序"
%Q和%q
1 2 3 4 5 6 7 8 name = "Ruby" str1 = %Q[Hello, #{name} !] p str1 str2 = %q[Hello, #{name} !] p str2
赶快拿起你的机械键盘吧,Happy Hacking with Ruby (: