【问题标题】:How do I using instance variables from within a lambda/Proc defined in a class variable?如何在类变量中定义的 lambda/Proc 中使用实例变量?
【发布时间】:2012-01-03 21:19:34
【问题描述】:

我写了以下代码:

class Actions
  def initialize
    @people = []
    @commands = {
      "ADD" => ->(name){@people << name },
      "REMOVE" => ->(n=0){ puts "Goodbye" },
      "OTHER" => ->(n=0){puts "Do Nothing" }
    }
  end
  def run_command(cmd,*param)
    @commands[cmd].call param if @commands.key?(cmd)
  end
  def people
    @people
  end
end
act = Actions.new

act.run_command('ADD','joe')
act.run_command('ADD','jack')
puts act.people

但是,当@commands 散列是类变量时,这可行,散列中的代码不知道@people 数组。

如何使@commands 哈希成为类变量,并且仍然能够访问特定的对象实例变量?

【问题讨论】:

  • 只是好奇为什么不将方法addremoveother定义为实例方法并使用respond_to?send来调用它们?
  • 为什么要@commands 成为类变量?
  • @Victor:一个很好的理由是它使访问控制更容易。如果您使用send 和方法,则需要单独列出允许使用run_command 的方法,使用哈希将可用命令及其实现收集到一个漂亮的整洁包中。
  • @mu 你就不能问respond_to?(cmd)吗?也就是说,为什么要单独列出允许的命令?
  • @mu send(cmd) if @allowed_methods.include?(cmd),如果您需要访问实例变量,它仍然比使用 lambda 哈希更干净。

标签: ruby oop proc-object


【解决方案1】:

您可以在调用 lambda 时使用 instance_exec 为 lambda 提供适当的上下文,查找 cmets 以查看更改:

class Actions
  # Move the lambdas to a class variable, a COMMANDS constant
  # would work just as well and might be more appropriate.
  @@commands = {
    "ADD"    => ->(name)  { @people << name   },
    "REMOVE" => ->(n = 0) { puts "Goodbye"    },
    "OTHER"  => ->(n = 0) { puts "Do Nothing" }
  }
  def initialize
    @people = [ ]
  end
  def run_command(cmd, *param)
    # Use instance_exec and blockify the lambdas with '&'
    # to call them in the context of 'self'. Change the
    # @@commands to COMMANDS if you prefer to use a constant
    # for this stuff.
    instance_exec(param, &@@commands[cmd]) if @@commands.key?(cmd)
  end
  def people
    @people
  end
end

【讨论】:

  • 啊哈! “参数作为块参数传递”到 instance_exec
【解决方案2】:

编辑遵循@VictorMoroz 和@mu 的建议:

class Actions
  def initialize
    @people = []
  end

  def cmd_add(name)
    @people << name
  end

  def cmd_remove
    puts "Goodbye"
  end

  def cmd_other
    puts "Do Nothing"
  end

  def people
    p @people
  end

  def run_command(cmd, *param)
    cmd = 'cmd_' + cmd.to_s.downcase
    send(cmd, *param) if respond_to?(cmd)
  end
end

act = Actions.new

act.run_command('add', 'joe')
act.run_command(:ADD, 'jill')
act.run_command('ADD', 'jack')

act.run_command('people') # does nothing

act.people

或者

class Actions
  ALLOWED_METHODS = %w( add remove other )

  def initialize
    @people = []
  end

  def add(name)
    @people << name
  end

  def remove
    puts "Goodbye"
  end

  def other
    puts "Do Nothing"
  end

  def people
    p @people
  end

  def run_command(cmd, *param)
    cmd = cmd.to_s.downcase
    send(cmd, *param) if ALLOWED_METHODS.include?(cmd)
  end
end

act = Actions.new

act.run_command('add', 'joe')
act.run_command(:add, 'jill')
act.run_command('add', 'jack')

act.run_command('people') # does nothing

act.people

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 2012-07-08
    • 1970-01-01
    • 2016-11-10
    • 1970-01-01
    • 2022-06-26
    相关资源
    最近更新 更多