在 Ruby 中定义 [方括号] 方法是如何工作的?
Posted
技术标签:
【中文标题】在 Ruby 中定义 [方括号] 方法是如何工作的?【英文标题】:How does defining [square bracket] method in Ruby work? 【发布时间】:2012-04-18 14:53:18 【问题描述】:我正在浏览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
我不明白定义 [ ] 方法的工作原理?
为什么key在[]外面,但是调用方法的时候却在[]里面?
key 可以不带括号吗?
我意识到有更好的方法来写这个,并且知道如何编写我自己的有效方法,但是这个 [ ] 方法让我感到困惑......非常感谢任何帮助,谢谢
【问题讨论】:
【参考方案1】: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"
【讨论】:
我认为 OP 是在问我们为什么不调用它:my_array.[]("key")
以及 my_array["key"] 可能如何工作......
所以根据定义,每当我在 ruby 中为某个类创建 [] 方法时,它都知道它正在某种数组上使用,并期望它稍后放入 [] 中的 (key) 参数?
您的代码中存在无限递归。我想你的意思是把电话转给super
。
@Gazler 修复你的代码。方法中的 super[key] 不起作用。 super(key).reverse 会。 super[key] = blah 不起作用。 super(key, value) 会。您应该重新了解如何在 ruby 方法中使用 super!
@Ben 你说的很对。我已经用超级电话更新了答案。【参考方案2】:
方括号是方法名称,例如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】:这只是语法糖。有某些语法模式会被翻译成消息发送。特别是
a + b
和
一样a.+(b)
同样适用于==
,!=
,<
,>
,<=
,>=
,<=>
,===
,&
,|
987654332 @、/
、-
、%
、**
、>>
、<<
、!==
、=~
和 !~
。
还有,
!a
和
一样a.!
同样适用于~
。
那么,
+a
和
一样a.+@
同样适用于-
。
另外,
a.(b)
和
一样a.call(b)
setter 也有特殊的语法:
a.foo = b
和
一样a.foo=(b)
最后但并非最不重要的一点是,索引有特殊的语法:
a[b]
和
一样a.[](b)
和
a[b] = c
和
一样a.[]=(b, c)
【讨论】:
你的清单让我想到了 Ruby 的糖。有趣的是,字符串插值器#
(例如"say hi, #my_name"
)不是方法调用的糖。镐书索引的第一页有一个很好的列表。
@SooDesuNe:它确实但是调用to_s
。【参考方案4】:
它是一个运算符重载器,它覆盖或补充您定义的类中的方法的行为,或者您正在修改其行为的类。您可以对不同于 [] 的其他运算符执行此操作。在这种情况下,您正在修改 [] 在类 SongList 的任何实例上调用它时的行为。
如果你有歌曲列表 = SongList.new 然后你做 songlist["foobar"] 然后您的自定义 def 将开始运行,并假定“foobar”将作为参数(键)传递,并且它将对“foobar”执行任何方法所说的对键执行的操作。
试试
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
【讨论】:
以上是关于在 Ruby 中定义 [方括号] 方法是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章