在 Ruby 中,'new' 和 'initialize' 之间的关系是什么?初始化时如何返回nil?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10383535/
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
In Ruby, what's the relationship between 'new' and 'initialize'? How to return nil while initializing?
提问by Chris Xue
What I want is:
我想要的是:
obj = Foo.new(0) # => nil or false
This doesn't work:
这不起作用:
class Foo
def initialize(val)
return nil if val == 0
end
end
I know in C/C++/Java/C#, we cant return a value in a constructor.
我知道在 C/C++/Java/C# 中,我们不能在构造函数中返回值。
But I'm wondering whether it is possible in Ruby.
但我想知道在 Ruby 中是否可行。
回答by J?rg W Mittag
In Ruby, what's the relationship between '
new' and 'initialize'?
在 Ruby 中,'
new' 和 'initialize'之间的关系是什么?
newtypically calls initialize. The default implementation of newis something like:
new通常调用initialize. 的默认实现new类似于:
class Class
def new(*args, &block)
obj = allocate
obj.initialize(*args, &block)
# actually, this is obj.send(:initialize, …) because initialize is private
obj
end
end
But you can, of course, override it to do anything you want.
但是你当然可以覆盖它来做任何你想做的事情。
How to return nil while initializing?
What I want is:
obj = Foo.new(0) # => nil or falseThis doesn't work:
class Foo def initialize(val) return nil if val == 0 end endI know in C/C++/Java/C#, we cant return a value in a constructor.
But I'm wondering whether it is possible in Ruby.
初始化时如何返回nil?
我想要的是:
obj = Foo.new(0) # => nil or false这不起作用:
class Foo def initialize(val) return nil if val == 0 end end我知道在 C/C++/Java/C# 中,我们不能在构造函数中返回值。
但我想知道在 Ruby 中是否可行。
There is no such thing as a constructorin Ruby. In Ruby, there are only methods, and they can return values.
Ruby 中没有构造函数这样的东西。在 Ruby 中,只有方法,它们可以返回值。
The problem you are seeing is simply that you want to change the return value of one method but you are overriding a different method. If you want to change the return value of method bar, you should override bar, not some other method.
您看到的问题只是您想更改一个方法的返回值,但您正在覆盖不同的方法。如果要更改 method 的返回值bar,则应覆盖bar,而不是其他方法。
If you want to change the behavior of Foo::new, then you should change Foo::new:
如果你想改变 的行为Foo::new,那么你应该改变Foo::new:
class Foo
def self.new(val)
return nil if val.zero?
super
end
end
Note, however, that this is a really bad idea, since it violates the contract of new, which is to return a fully initialized, fully functioning instance of the class.
但是请注意,这是一个非常糟糕的主意,因为它违反了 的约定new,即返回一个完全初始化的、功能齐全的类实例。
回答by Gareth
There are important differences between the two methods.
这两种方法之间存在重要区别。
newis a classmethod, which generally creates an instance of the class (this deals with the tricky stuff like allocating memory that Ruby shields you from so you don't have to get too dirty).
new是一个类方法,它通常创建类的一个实例(这处理棘手的事情,例如分配内存,Ruby 保护您免受此类问题的影响,因此您不必太脏)。
Then, initialize, an instancemethod, tells the object to set its internal state up according to the parameters requested.
然后,initialize一个实例方法告诉对象根据请求的参数设置其内部状态。
Either of these can be overridden depending on what you want. For example, Foo.newmight actually create and return an instance of FooSubclassif it needs to be clever enough to do that.
根据您的需要,可以覆盖其中任何一个。例如,如果它需要足够聪明才能做到这一点,它Foo.new实际上可能会创建并返回一个实例FooSubclass。
However, often it's better to delegate use cases like these to other class methods which are more explicit about what they do, for example Foo.relating_to(bar). Breaking other peoples expectations about what methods like newshould do will confuse people more than it will help them in the long run.
但是,通常最好将此类用例委托给其他更明确的类方法,例如Foo.relating_to(bar). 打破其他人对方法new应该做什么的期望只会让人们感到困惑,而不是从长远来看对他们有帮助。
As an example, look at the implementation of Singleton, a module which allows only one instance of a particular class to exist. It makes the newmethod private, and exposes an instancemethod which either returns the existing instance of the object, or calls newif it hasn't been created yet.
作为一个例子,看看 的实现Singleton,一个模块只允许一个特定类的一个实例存在。它使new方法私有,并公开一个instance方法,该方法返回对象的现有实例,或者new在尚未创建时调用。
回答by Flexoid
You can something like this:
你可以这样:
class Foo
def self.init(val)
new(val) unless val == 0
end
def initialize(val)
#...
end
end
Example of usage:
用法示例:
obj = Foo.init(0)
=> nil
obj = Foo.init(5)
=> #<Foo:0x00000002970a98>
回答by Andrew Grimm
Wanting to do
想做
class Foo
def initialize(val)
return nil if val == 0
end
end
would make for inconsistent code.
会导致代码不一致。
If you had
如果你有
class Foo
def initialize(val)
return nil if val == 0
@val = val
@bar = 42
end
end
what would you want to get back if you did Foo.new(1)? Would you want 42(the return value for Foo#initialize), or a fooobject? If you want a fooobject for Foo.new(1), then why would you expect return nilto make Foo.new(0)return nil?
如果你这样做了,你想得到什么Foo.new(1)?你想要42( 的返回值Foo#initialize),还是一个foo对象?如果你想foo为对象Foo.new(1),那么为什么你会希望return nil做Foo.new(0)回零?
回答by lucifer
It is solved by simply creating an object variable like this:
它可以通过简单地创建一个像这样的对象变量来解决:
class Foo
def initialize(val)
@val = val
return nil if @val == 0
end
end
obj = Foo.new(0)
Output:-
=>#<Foo:0x1243b8 @val=0>
The output varies in different computers.
输出在不同的计算机上有所不同。

