0

我的代码在该部分中有一个#符号。class_eval这对我来说很陌生,这是什么意思?

class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s # make sure it's a string
    attr_reader attr_name # create the attribute's getter
    attr_reader attr_name+"_history" # create bar_history getter
    class_eval %Q{
def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end
}
  end
end
4

3 回答 3

4

此功能称为字符串插值。它的有效作用是#{attr_name}attr_name实际价值代替。您发布的代码显示了一种用例 - 当您想在运行时使用具有通用名称的变量时。

然后更经常使用的用例如下:

您可以这样使用字符串:"Hello, #{name}!"并且#{name}会在此处自动替换 - 这是非常方便的功能。语法糖。

但请注意%Q代码 - 这会将以下代码转换为字符串,然后传递给class_eval并在那里执行。在这里查看更多信息。没有它,它当然是行不通的。

于 2013-07-19T13:11:59.603 回答
2
def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end

如果attr_name变量等于,比方说,"params"。这实际上会变成这样:

def params=(attr_name)
@params = attr_name
@params_history = [nil] if @params_history.nil?
@params_history << attr_name
end

为什么会这样?因为所谓的字符串插值。如果您#{something}在字符串中写入,something将在该字符串中进行评估和替换。

为什么上面的代码即使不在字符串中也能工作?

答案是,因为它是!

Ruby 为您提供了不同的处理方式,并且对于某些文字有另一种语法,就像这样:只要您使用相同或相应的结束符,%w{one two three}哪里可以是任何分隔符。{}所以它可能是%w\one two three\or %w[one two three],它们都会起作用。

那个,%w用于数组,%Q用于双引号字符串。如果你想看到所有这些,我建议你看看这个:http ://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

现在,在那个代码中

class Class
  def attr_accessor_with_history(attr_name)
    attr_name = attr_name.to_s # make sure it's a string
    attr_reader attr_name # create the attribute's getter
    attr_reader attr_name+"_history" # create bar_history getter
    class_eval %Q{ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # STRING BEGINS
def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end
} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # STRING ENDS
  end
end

我们可以看到带有字符串插值的整个部分都在一个%Q{ }. 这意味着整个块是一个大的双引号字符串。这就是为什么字符串插值会在将字符串发送到 eval 之前成功完成它的工作。

于 2013-07-19T13:34:38.947 回答
2

为什么下一个代码在 class_eval 中有 #?

这是字符串插值。

一个例子:

x = 12
puts %Q{ the numer is #{x} }
# >>  the numer is 12 

%Q这里

当字符串中有更多引号字符时,这是双引号字符串的替代方法。而不是在它们前面放置反斜杠。

于 2013-07-19T13:10:21.133 回答