我正在经历Programming Ruby - a pragmatic programmers guide并且偶然发现了这段代码:
class SongList
def [](key)
if key.kind_of?(Integer)
return @songs[key]
else
for i in 0...@songs.length
return @songs[i] if key == @songs[i].name
end
end
return nil
end
end
我不明白定义[]方法是如何工作的?
为什么键在[]之外,但是当调用该方法时,它在[]内?
键可以没有括号吗?
我意识到有更好的方法来写这个,并且知道如何编写我自己的方法,但是这个[]方法让我感到困惑...非常感谢任何帮助,谢谢
答案 0 :(得分:44)
这只是语法糖。某些语法模式可以转换为消息发送。特别是
a + b
与
相同a.+(b)
同样适用于==
,!=
,<
,>
,<=
,>=
,<=>
, ===
,&
,|
,*
,/
,-
,%
,**
,{{ 1}},>>
,<<
,!==
和=~
。
另外,
!~
与
相同!a
同样适用于a.!
。
然后,
~
与
相同+a
同样适用于a.+@
。
另外,
-
与
相同a.(b)
setter还有特殊的语法:
a.call(b)
与
相同a.foo = b
最后但并非最不重要的是,索引有特殊的语法:
a.foo=(b)
与
相同a[b]
和
a.[](b)
与
相同a[b] = c
答案 1 :(得分:37)
与许多语言不同,ruby中的方法可以包含一些特殊字符。其中之一是数组查找语法。
如果您要实现自己的哈希类,在哈希中检索项目时,您想要反转它,您可以执行以下操作:
class SillyHash < Hash
def [](key)
super.reverse
end
end
您可以通过使用以下内容调用哈希来证明这一点:
a = {:foo => "bar"}
=> {:foo=>"bar"}
a.[](:foo)
=> "bar"
a.send(:[], :foo)
=> "bar"
因此def []定义了my_array["key"]
时使用的方法。其他可能看起来很奇怪的方法是:
class SillyHash < Hash
def [](key)
super.reverse
end
def []=(key, value)
#do something
end
def some_value=(value)
#do something
end
def is_valid?(value)
#some boolean expression
end
end
为了澄清,[]
方法的定义与数组或散列无关。采取以下(人为的)示例:
class B
def []
"foo"
end
end
B.new[]
=> "foo"
答案 2 :(得分:8)
方括号是Array#size
方法名称,你有Array#[]
作为方法,你甚至可以像任何其他方法一样使用它:
array = [ 'a', 'b', 'c']
array.[](0) #=> 'a'
array.[] 1 #=> 'b'
array[2] #=> 'c'
最后一个就像语法糖一样,与第一个完全相同。 Array#+
的工作类似:
array1 = [ 'a', 'b' ]
array2 = [ 'c', 'd' ]
array1.+(array2) #=> [ 'a', 'b', 'c', 'd' ]
array1.+ array2 #=> [ 'a', 'b', 'c', 'd' ]
array1 + array2 #=> [ 'a', 'b', 'c', 'd' ]
你甚至可以添加这样的数字:
1.+(1) #=> 2
1.+ 1 #=> 2
1 + 1 #=> 2
同样适用于/
,*
,-
等等。
答案 3 :(得分:0)
它是一个操作符重载程序,它会覆盖或补充您定义的类中的方法的行为,或者您要修改的行为的类。您可以对不同于[]的其他运算符执行此操作。在这种情况下,当在SongList类的任何实例上调用它时,您正在修改[]的行为。
如果你有songlist = SongList.new 然后你做歌曲列表[&#34; foobar&#34;] 然后你的自定义def将开始运作,并假设&#34; foobar&#34;将作为参数(键)传递,它将对&#34; foobar&#34;无论方法说什么都应该做到关键。
尝试
class Overruler
def [] (input)
if input.instance_of?(String)
puts "string"
else
puts "not string"
end
end
end
foo = Overruler.new
foo["bar"].inspect
foo[1].inspect