在类方法中使用实例变量 - Ruby
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9311347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using Instance Variables in Class Methods - Ruby
提问by tackleberry
I have a class something like below, and I used instance variables (array) to avoid using lots of method parameters.
我有一个类似下面的类,我使用实例变量(数组)来避免使用大量方法参数。
It works as I expected but is that a good practice? Actually I wouldn't expect that worked, but I guess class methods are not working as static methods in other languages.
它按我的预期工作,但这是一个好习惯吗?实际上,我认为这不会奏效,但我猜类方法在其他语言中不能作为静态方法工作。
class DummyClass
def self.dummy_method1
@arr = []
# Play with that array
end
def self.dummy_method2
# use @arr for something else
end
end
回答by Steven
The reason instance variables work on classes in Ruby is that Ruby classes areinstances themselves (instances of class Class). Try it for yourself by inspecting DummyClass.class. There are no "static methods" in the C# sense in Ruby because every method is defined on (or inherited into) some instance and invoked on some instance. Accordingly, they can access whatever instance variables happen to be available on the callee.
实例变量对 Ruby 中的类起作用的原因是 Ruby 类本身就是实例(类Class 的实例)。通过检查自己尝试一下DummyClass.class。Ruby 中没有 C# 意义上的“静态方法”,因为每个方法都是在某个实例上定义(或继承到)某个实例上并在某个实例上调用的。因此,它们可以访问在被调用方上碰巧可用的任何实例变量。
Since DummyClassis an instance, it can have its own instance variables just fine. You can even access those instance variables so long as you have a reference to the class (which should be always because class names are constants). At any point, you would be able to call ::DummyClass.instance_variable_get(:@arr)and get the current value of that instance variable.
由于DummyClass是一个实例,它可以有自己的实例变量就好了。您甚至可以访问这些实例变量,只要您有对类的引用(这应该总是因为类名是常量)。在任何时候,您都可以调用::DummyClass.instance_variable_get(:@arr)并获取该实例变量的当前值。
As for whether it's a good thing to do, it depends on the methods.
至于做的好不好,要看方法。
If @arris logically the "state" of the instance/class DummyClass, then store it in instance variable. If @arris only being used in dummy_method2as an operational shortcut, then pass it as an argument. To give an example where the instance variable approach is used, consider ActiveRecord in Rails. It allows you to do this:
如果@arr逻辑上是 instance/class 的“状态” DummyClass,则将其存储在实例变量中。如果@arr仅用dummy_method2作操作快捷方式,则将其作为参数传递。要举例说明使用实例变量方法,请考虑 Rails 中的 ActiveRecord。它允许你这样做:
u = User.new
u.name = "foobar"
u.save
Here, the name that has been assigned to the user is data that is legitimately on the user. If, before the #savecall, one were to ask "what is the name of the user at this point", you would answer "foobar". If you dig far enough into the internals (you'll dig very far and into a lot of metaprogramming, you'll find that they use instance variables for exactly this).
这里,分配给用户的名称是用户合法的数据。如果在#save通话之前有人问“此时用户的姓名是什么”,你会回答“foobar”。如果您深入挖掘内部结构(您将深入挖掘大量元编程,您会发现它们正是为此使用实例变量)。
The example I've used contains two separate public invocations. To see a case where instance variables are still used despite only one call being made, look at the ActiveRecord implementation of #update_attributes. The method body is simply load(attributes, false) && save. Why does #savenot get passed any arguments (like the new name) even though it is going to be in the body of save where something like UPDATE users SET name='foobar' WHERE id=1;? It's because stuff like the name is information that belongs on the instance.
我使用的示例包含两个单独的公共调用。要查看仅进行一次调用但仍使用实例变量的情况,请查看#update_attributes. 方法体很简单load(attributes, false) && save。为什么不#save传递任何参数(如 new name),即使它会在 save 的主体中,例如UPDATE users SET name='foobar' WHERE id=1;?这是因为名称之类的东西是属于实例的信息。
Conversely, we can look at a case where instance variables would make no sense to use. Look at the implementation of #link_to_if, a method that accepts a boolean-ish argument (usually an expression in the source code) alongside arguments that are ordinarily accepted by #link_tosuch as the URL to link to. When the boolean condition is truthy, it needs to pass the rest of the arguments to #link_toand invoke it. It wouldn't make much sense to assign instance variables here because you would not say that the invoking context here (the renderer) contains that information in the instance. The renderer itself does not have a "URL to link to", and consequently, it should not be buried in an instance variable.
相反,我们可以看看实例变量没有意义使用的情况。看看 的实现#link_to_if,该方法接受布尔型参数(通常是源代码中的表达式)以及通常被#link_to链接到的 URL 等参数。当布尔条件为真时,它需要将其余参数传递给#link_to并调用它。在此处分配实例变量没有多大意义,因为您不会说此处的调用上下文(渲染器)在实例中包含该信息。渲染器本身没有“链接到的 URL”,因此,不应将其隐藏在实例变量中。
回答by Frederick Cheung
Those are class instance variables and are a perfectly legitimate things in ruby: classes are objects too (instances of Class) and so have instance variables.
这些是类实例变量,在 ruby 中是完全合法的东西:类也是对象(类的实例),因此具有实例变量。
One thing to look out for is that each subclass will have its own set of class instance variables (after all these are different objects): If you subclassed DummyClass, class methods on the subclass would not be able to see @arr.
需要注意的一件事是每个子类都有自己的一组类实例变量(毕竟这些是不同的对象):如果您子类化DummyClass,子类上的类方法将无法看到@arr.
Class variables (@@foo) are of course the other way round: the entire class hierarchy shares the same class variables.
类变量 ( @@foo) 当然是相反的:整个类层次结构共享相同的类变量。

