如何在Ruby中定义[方括号]方法?

时间:2012-04-04 20:40:22

标签: ruby methods

我正在经历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

我不明白定义[]方法是如何工作的?

为什么键在[]之外,但是当调用该方法时,它在[]内?

键可以没有括号吗?

我意识到有更好的方法来写这个,并且知道如何编写我自己的方法,但是这个[]方法让我感到困惑...非常感谢任何帮助,谢谢

4 个答案:

答案 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