52

我正在阅读Programming Ruby - 一个务实的程序员指南,并偶然发现了这段代码:

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在[]外面,但是调用方法的时候却在[]里面?

键可以不带括号吗?

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

4

4 回答 4

52

这只是语法糖。有某些语法模式会被翻译成消息发送。尤其

a + b

是相同的

a.+(b)

这同样适用于==, !=, <, >, <=, >=, <=>, ===, &, |, *, /, -, %, **, >>, <<, !==,=~以及!~

还,

!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)
于 2012-04-05T01:19:53.370 回答
42

与许多语言不同,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" 
于 2012-04-04T20:43:43.660 回答
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

同样适用于/,*等等-

于 2012-04-04T21:00:26.953 回答
0

它是一个运算符重载器,它覆盖或补充您定义的类中的方法的行为,或者您正在修改其行为的类。您可以对不同于 [] 的其他运算符执行此操作。在这种情况下,当在类 SongList 的任何实例上调用 [] 时,您正在修改它的行为。

如果你有 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
于 2018-01-26T22:09:45.923 回答