Ruby的按位移位运算符“ <<”的困惑

YKY*_*YKY 1 ruby ruby-on-rails

我正在研究Ruby,无法弄清楚。我有一个练习,必须在其中包含游戏的Library类中添加一个方法。每个游戏都是类Game的一个实例。因此,解决方案如下:

class Library
  attr_accessor :games

  def initialize(games)
    self.games = games
  end

  def has_game?(search_game)
    for game in games
      return true if game == search_game
    end
    false
  end

  def add_game(game)
    @games << game
  end
end
Run Code Online (Sandbox Code Playgroud)

我不明白<<在这种情况下如何工作。这是按位左移吗?是图书馆类只是假设它games是一个数组,我相信我可以在初始化,单个游戏或一系列游戏时将任何东西传递给图书馆类吗?

Car*_*and 5

当你有:

@games << game
Run Code Online (Sandbox Code Playgroud)

<<实际上是一种方法。您会问,如果这是一种方法,为什么不以通常的方式编写:

@games.<<(game)
Run Code Online (Sandbox Code Playgroud)

?实际上,您可以这样写,并且可以正常工作。许多Ruby方法的名称都是符号。有几个人是+-**&||%。Ruby知道您更喜欢编写2+3而不是2.+(3),因此让我们让您做前者(然后悄悄地将其转换为后者)。这种调节通常被称为“语法糖”。

<<是一个@games的方法(和game<<的说法),因为@games接收器的方法的<<(技术上:<<)。在历史上,它被称为“接收方”,因为使用OOP可以将方法“发送”给接收方。

地说,<<是的方法@games装置,其<<是一种实例方法@games的类。因此,我们有:

@games.methods.include?(:<<) #=> true
@games.class.instance_methods.include?(:<<) #=> true
Run Code Online (Sandbox Code Playgroud)

我希望@games是该类的一个实例ArrayArray的实例方法在此处列出。例如:

@games = [1,2,3]
@games.class     #=> [1,2,3].class => Array
@games << 4      #=> [1,2,3,4]
@games.<<(5)     #=> [1,2,3,4,5]
Run Code Online (Sandbox Code Playgroud)

另一方面,假设@games是的一个实例Fixnum。例如:

@games = 7
@games.class     #=> 7.class => Fixnum
Run Code Online (Sandbox Code Playgroud)

二进制形式如下:

@games.to_s(2)   #=> "111"
Run Code Online (Sandbox Code Playgroud)

然后:

@games << 2      #=> 28
28.to_s(2)       #=> "11100"
Run Code Online (Sandbox Code Playgroud)

因为<<Fixnum类的实例方法。

作为第三个示例,假设@games有一个哈希:

@games = { :a => 1 }
@games.class     #=> { :a => 1 }.class => Hash
Run Code Online (Sandbox Code Playgroud)

然后:

@games << { :b => 2 }
  #=> NoMethodError: undefined method `<<' for {:a=>1}:Hash
Run Code Online (Sandbox Code Playgroud)

从错误消息中可以清楚地看出问题。Hash类没有实例方法<<

最后一件事:考虑方法Object#send。回想起初,我曾说过方法是发送给接收者的。而不是写:

@games = [1,2,3]
@games << 4         #=> [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

你可以这样写:

@games.send(:<<, 4) #=> [1, 2, 3, 4] 
Run Code Online (Sandbox Code Playgroud)

这就是您应该如何考虑方法和接收者的方式。因为send是类的实例方法Object,并且所有对象都继承了Object实例方法,所以我们看到这send是向接收方“发送”方法(:<<,也可以表示为字符串"<<")和它的参数(这里只是4)。

偶然地,有时候您必须使用send来调用方法。首先,send使用privateprotected方法。另外,您可以send在要动态调用方法时使用,其中方法的名称是变量的值。

总之,要了解method它的作用:

receiver.method(*args)
Run Code Online (Sandbox Code Playgroud)

methodreceiver的类中查找实例方法的文档。例如,如果您使用Google“红宝石数组”,则第一个匹配项可能是class 的文档Array