【问题标题】:How can I call a class method in Ruby with the method name stored in an array?如何使用存储在数组中的方法名称在 Ruby 中调用类方法?
【发布时间】:2015-07-18 03:42:17
【问题描述】:

我目前正在用 Ruby 开发一款扑克游戏。我没有使用大量 if-else 语句来检查玩家手牌的价值,而是决定执行以下操作:

  #calculate the players score
  def score
    POSS.map {|check|
      if (check[1].call())
        @score = check[0]
        puts @score
        return check[0]
      else
        false
      end
    }
  end

      POSS = [
    [10, :royal_flush?],
    [9, :straight_flush?],
    [8, :four_kind?],
    [7, :full_house?],
    [6, :flush?],
    [5, :straight?],
    [4, :three_kind?],
    [3, :two_pairs?],
    [2, :pair?]
  ]

“POSS”的每一项中的第二项是我创建的一种方法,用于检查玩家是否有那手牌。我正在尝试使用 .call() 调用该方法,但出现以下错误:

Player.rb:43:in `block in score': undefined method `call' for 
:royal_flush?:Symbol (NoMethodError)    from Player.rb:42:in `map'  from
Player.rb:42:in `score'     from Player.rb:102:in `get_score'   from
Player.rb:242:in `<main>'

【问题讨论】:

    标签: ruby-on-rails ruby methods


    【解决方案1】:

    http://ruby-doc.org/core-2.2.2/Object.html Object#send 是您正在寻找的方法。

    既然你想要一个“类方法”,那么在声明包含“类方法”的类的实例方法时,Object 应该是 self

    试试这个代码

     #calculate the players score
      def score
        POSS.map do |check|
          if self.send check[1] 
            @score = check[0]
            puts @score
            return check[0]
          else
            false
          end
        end
      end
    
          POSS = [
        [10, :royal_flush?],
        [9, :straight_flush?],
        [8, :four_kind?],
        [7, :full_house?],
        [6, :flush?],
        [5, :straight?],
        [4, :three_kind?],
        [3, :two_pairs?],
        [2, :pair?]
      ]
    

    风格因人而异,但是,我认为在使用多行块时,最好使用 'do,end' 对而不是 '{ }'

    https://github.com/bbatsov/ruby-style-guide

    我认为看起来像这样的代码可能会引起一些混乱

    foobar = ->(foo,bar){puts "Passed in #{foo}, #{bar}"}
    foobar.call("one","two")
    

    如果将第一行抽象到程序的其他部分,您可能会认为 foobar 是一个方法,但它实际上是一个 lambda。 Procs 和 Lambdas 就像方法一样,但更好......以它们自己的方式......查看这篇关于 Procs、Blocks 和 Lambdas 的文章。

    http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/

    如果有兴趣,请查看https://www.codecademy.com/forums/ruby-beginner-en-L3ZCI 了解更多关于 PBLS 的详细信息

    【讨论】:

    • 完美,非常感谢!感谢您的建议和链接,我一定会检查的!
    【解决方案2】:

    您可以使用send

    class Foo
      def self.bar
        "bar"
      end
    
      def baz
        "baz"
      end
    end
    
    Foo.send(:bar) # => "bar"
    f = Foo.new
    f.send(:baz) # => "baz"
    

    虽然我不确定这是否是您正在编写的应用程序的最佳方法。当你得到它的工作时,你可以将它发布到CodeReview

    【讨论】:

      【解决方案3】:

      没有方法就没有方法;并且有 no Symbol#call 导致立即错误。

      (或者更确切地说,a)调用方式是通过Object#__send__,提供名称和参数。也可以解析一个方法,然后调用它;但是__send__ 是最直接的路径,因为Ruby 是基于message passing

      也就是说,不要使用symbol.call(..),而是使用obj.__send__(symbol, ..)。 (在这种情况下,对象可能是self。)

      Understanding Ruby symbol as method call

      【讨论】:

      • 它继续给我同样的错误。我有royal_flush?之前定义的,它在单独测试时工作。这是我的电话与您建议的更改的样子:POSS.map {|check| if (Player.send check[1])
      • @PowerProject 没有方法就是没有方法。如果它给出了相同的错误(这将是相同的错误type,但是对于不同的接收器对象和方法名称),请参阅前面的内容。使用 obj.__send__(:x) 时,obj 上必须存在名为 x 的方法。在这种情况下,您可能不想使用Player(类),而是使用特定 播放器实例。如果您确实想使用一个类,请确保使用了 类方法
      • 问题是我在做 Player.send 而不是 @Schylar 提到的 self.send
      • @PowerProject 请参阅相关链接文档。这就是__send__ 的工作原理。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2018-02-08
      • 1970-01-01
      • 2013-12-06
      • 2017-09-26
      相关资源
      最近更新 更多