Ruby:是否自动将实例变量设置为方法参数?

Ruby:是否自动将实例变量设置为方法参数?,ruby,methods,instance-variables,argument-passing,Ruby,Methods,Instance Variables,Argument Passing,是否有计划实现类似于CoffeeScript的ruby行为,即在方法参数列表中指定实例变量名? 像 我知道这个问题:,但是所有的解决方案(包括我自己的)似乎都不符合ruby的简单性哲学 而且,这种行为会有什么负面影响吗 更新 其中一个原因是ruby社区的枯燥(不要重复你自己)哲学。我经常发现自己需要重复参数变量的名称,因为我希望将其分配给同名的实例变量 def initialize(name) # not DRY @name = name end 我能想到的一个缺点是,如果一个方法没有

是否有计划实现类似于CoffeeScript的ruby行为,即在方法参数列表中指定实例变量名? 像

我知道这个问题:,但是所有的解决方案(包括我自己的)似乎都不符合ruby的简单性哲学

而且,这种行为会有什么负面影响吗

更新

其中一个原因是ruby社区的枯燥(不要重复你自己)哲学。我经常发现自己需要重复参数变量的名称,因为我希望将其分配给同名的实例变量

def initialize(name)
  # not DRY
  @name = name
end
我能想到的一个缺点是,如果一个方法没有主体,它看起来好像什么都不做。如果你扫描得很快,这看起来像是一个禁区。但我认为,给时间,我们可以适应

另一个缺点是:如果你在主体中设置其他实例变量,并试图通过将所有赋值放在开头来让人可读,那么需要更多的认知“能力”才能看到在参数列表中也有赋值。但我不认为这比看到一个常量或方法调用并跳转到它的定义更难

# notice: instance var assignments are happening in 2 places! 
def initialize(@name)
  @errors = []
end

我想你回答了你自己的问题,它不符合ruby的简单性哲学。这将增加方法中参数处理方式的复杂性,并将管理变量的逻辑向上移动到方法参数中。我可以看到这样的论点,即它使代码的可读性降低了,但它确实让我觉得不是很冗长

@param必须应对的一些场景:

def initialize( first, last, @scope, @opts = {} )

def search( @query, condition )

def ratchet( @*arg  ) 
所有这些场景都应该有效吗?只需
初始化
?在我看来,
@*arg
似乎特别危险。所有这些规则和排除使得Ruby语言更加复杂。对于自动实例变量的好处,我认为这不值得

实际上

class User
  define_method(:initialize) { |@name| }
end

User.new(:name).instance_variable_get :@name
# => :name

适用于1.8.7,但不适用于1.9.3。现在,我是从哪里了解到这一点的…

经过深思熟虑,我想知道是否有可能从ruby方法中获得参数名称。如果是这样的话,我可以使用一个特殊的参数前缀,比如“iv_”,来指示应该将哪些参数设置为实例变量

这是可能的:

对!!所以我可以写一个模块来处理这个问题。然后我陷入困境,因为如果我调用模块的helper方法,它不知道参数的值,因为它们是调用方的本地参数。啊,但是ruby有绑定对象

以下是模块(仅限ruby 1.9):

输出:

[:iv_name, "Methuselah"]
[:age, 969]
[:@name, "Methuselah"]
[:@age, nil]
#<User:0x00000101089448 @name="Methuselah">
[:iv_名称,“玛土撒拉”]
[:年龄,969]
[:@name,“玛土撒拉”]
[:@age,无]
#
它不允许您有一个空的方法体,但它是干的。我相信,只需指定哪些方法应该具有这种行为(通过alias_方法实现),而不是在每个方法中调用slurp_参数,就可以进一步增强它——不过,必须在定义所有方法之后才能进行规范


请注意,模块和助手方法名称可能会有所改进。我只是用了我想到的第一件事

我会设想一个飞溅的实例arg是
*@arg
。除此之外,没有一个场景看起来特别丑陋、复杂,甚至难以理解。就实例变量逻辑而言,您已经可以在arg列表中设置它们,尽管是以一种人为的方式:
def run(a=(@v=1));结束
。是的,这是一个丑陋的设计,只有在未传递arg时才设置var。但这表明这种分配已经被允许了。我认为这有助于保持代码干燥剂。我想在我的问题上再加一个例子。哎呀,当我说这会让代码更枯燥时,我指的是我问题中的建议,而不是我评论中的人为例子。+1代表勇敢的尝试。我还没有试过,但如果1.9.3不起作用,那就更新奇了。谢谢你的回答。不过,似乎还有更多值得做的工作。:)@杰奎克你真的只需要做一次安装。然后在类中,只需调用
enable\u for
slurp\u args
module InstanceVarsFromArgsSlurper
  # arg_prefix must be a valid local variable name, and I strongly suggest
  # ending it with an underscore for readability of the slurped args.
  def self.enable_for(mod, arg_prefix)
    raise ArgumentError, "invalid prefix name" if arg_prefix =~ /[^a-z0-9_]/i
    mod.send(:include, self)
    mod.instance_variable_set(:@instance_vars_from_args_slurper_prefix, arg_prefix.to_s)
  end

  def slurp_args(binding)
    defined_prefix = self.class.instance_variable_get(:@instance_vars_from_args_slurper_prefix)
    method_name = caller[0][/`.*?'/][1..-2]
    param_names = method(method_name).parameters.map{|p| p.last.to_s }
    param_names.each do |pname|
      # starts with and longer than prefix
      if pname.start_with?(defined_prefix) and (pname <=> defined_prefix) == 1
        ivar_name = pname[defined_prefix.size .. -1]
        eval "@#{ivar_name} = #{pname}", binding
      end
    end
    nil
  end
end
class User
  InstanceVarsFromArgsSlurper.enable_for(self, 'iv_')

  def initialize(iv_name, age)
    slurp_args(binding)  # this line does all the heavy lifting
    p [:iv_name, iv_name]
    p [:age, age]
    p [:@name, @name]
    p [:@age, @age]
  end
end

user = User.new("Methuselah", 969)
p user
[:iv_name, "Methuselah"]
[:age, 969]
[:@name, "Methuselah"]
[:@age, nil]
#<User:0x00000101089448 @name="Methuselah">