延续“隐藏的特性...”模式,让我们分享Ruby编程语言中不太为人知但有用的特性。
尝试限制此讨论只涉及核心Ruby,没有任何Ruby on Rails的东西。
另请参见:
(请每个答案仅回答一个隐藏特性。)
谢谢
延续“隐藏的特性...”模式,让我们分享Ruby编程语言中不太为人知但有用的特性。
尝试限制此讨论只涉及核心Ruby,没有任何Ruby on Rails的东西。
另请参见:
(请每个答案仅回答一个隐藏特性。)
谢谢
从 Ruby 1.9 版本开始,Proc#=== 是 Proc#call 的别名,这意味着 Proc 对象可以像这样在 case 语句中使用:
def multiple_of(factor)
Proc.new{|product| product.modulo(factor).zero?}
end
case number
when multiple_of(3)
puts "Multiple of 3"
when multiple_of(7)
puts "Multiple of 7"
end
Peter Cooper在他的Ruby技巧清单中有一些不错的技巧。其中我最喜欢的是允许枚举单个元素和集合。
也就是说,将一个非集合对象视为只包含该对象的集合。
它的代码如下所示:
[*items].each do |item|
# ...
end
items
是一个字符串,你不必用 [*…] 把它括起来。String.each 不会像一些人期望的那样迭代字符,它只是将自身返回给块。 - mxcl我不确定这个方法有多少人知道,但在需要将一维数组转换为哈希表时,我发现它非常有用:
fruit = ["apple","red","banana","yellow"]
=> ["apple", "red", "banana", "yellow"]
Hash[*fruit]
=> {"apple"=>"red", "banana"=>"yellow"}
Hash[ [["apple","red"], ["banana","yellow"] ]
产生相同的结果。 - Marc-André Lafortune我喜欢的一个技巧是在非数组对象上使用splat (*
) 扩展符。以下是在正则表达式匹配中的示例:
match, text, number = *"Something 981".match(/([A-z]*) ([0-9]*)/)
其他例子包括:
a, b, c = *('A'..'Z')
Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
text, number = *"text 555".match(/regexp/)[1..-1]
。 - Andrew Grimmtext, number = "Something 981".scan(/([A-z]*) ([0-9]*)/).flatten.map{|m| Integer(m) rescue m}
- Jonas Elfström哇,没有人提到触发器操作符:
1.upto(100) do |i|
puts i if (i == 3)..(i == 15)
end
i == 3
时,其状态会转换为 true,而在 i != 3
并且 i == 15
后则会转换为 false。类似于电子器件中的 flip-flop:http://en.wikipedia.org/wiki/Flip-flop_%28electronics%29。 - Konstantin HaaseRuby 的一个酷炫之处在于,你可以在其他编程语言不允许的位置调用方法并运行代码,比如在方法或类定义中。
例如,要创建一个具有未知超类(即随机)的类,您可以执行以下操作:
class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
end
RandomSubclass.superclass # could output one of 6 different classes.
这里使用的是1.9版本中的Array#sample
方法(在1.8.7版本中,可以使用Array#choice
方法),虽然示例有点牵强,但你能看到它的威力。
另一个很酷的例子是能够设置非固定的默认参数值(就像其他语言经常要求的那样):
def do_something_at(something, at = Time.now)
# ...
end
当然,第一个示例的问题在于它在定义时被评估,而不是在调用时。因此,一旦选择了一个超类,它将在程序的其余部分中保持为该超类。
但是,在第二个示例中,每次调用do_something_at
时,at
变量将是方法被调用的时间(非常接近)。
require 'activesupport'
一样轻松地在Rails之外使用它。 - rfunduk另一个微小的特性 - 可以将一个Fixnum
转换成任何不超过36的进制:
>> 1234567890.to_s(2)
=> "1001001100101100000001011010010"
>> 1234567890.to_s(8)
=> "11145401322"
>> 1234567890.to_s(16)
=> "499602d2"
>> 1234567890.to_s(24)
=> "6b1230i"
>> 1234567890.to_s(36)
=> "kf12oi"
正如Huw Walters所评论的那样,另一种转换方法同样简单:
>> "kf12oi".to_i(36)
=> 1234567890
String#to_s(base)
将字符串转换回整数;例如"1001001100101100000001011010010".to_i(2)
,"499602d2".to_i(16)
等都会返回原始的Fixnum
。 - Huw Walters带有默认值的散列!在这种情况下是一个数组。
parties = Hash.new {|hash, key| hash[key] = [] }
parties["Summer party"]
# => []
parties["Summer party"] << "Joe"
parties["Other party"] << "Jane"
在元编程中非常有用。
在1.9版中,另一个有趣的补充是Proc#curry功能,它允许您将接受n个参数的Proc转换为接受n-1个参数的函数。这里将其与我上面提到的Proc#===技巧相结合使用:
it_is_day_of_week = lambda{ |day_of_week, date| date.wday == day_of_week }
it_is_saturday = it_is_day_of_week.curry[6]
it_is_sunday = it_is_day_of_week.curry[0]
case Time.now
when it_is_saturday
puts "Saturday!"
when it_is_sunday
puts "Sunday!"
else
puts "Not the weekend"
end
下载 Ruby 1.9 源码,然后运行 make golf
命令,接着你就可以像这样做:
make golf
./goruby -e 'h'
# => Hello, world!
./goruby -e 'p St'
# => StandardError
./goruby -e 'p 1.tf'
# => 1.0
./goruby19 -e 'p Fil.exp(".")'
"/home/manveru/pkgbuilds/ruby-svn/src/trunk"
阅读 golf_prelude.c
可以找到更多隐藏的有趣内容。