Я хочу:
obj = Foo.new(0) # => nil or false
Это не работает:
class Foo
def initialize(val)
return nil if val == 0
end
end
Я знаю в C/С++/Java/С#, мы не можем вернуть значение в конструкторе.
Но мне интересно, возможно ли это в Ruby.
Я хочу:
obj = Foo.new(0) # => nil or false
Это не работает:
class Foo
def initialize(val)
return nil if val == 0
end
end
Я знаю в C/С++/Java/С#, мы не можем вернуть значение в конструкторе.
Но мне интересно, возможно ли это в Ruby.
В Ruby, какая связь между "
new
" и "initialize
"?
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
Но вы можете, конечно, переопределить его, чтобы делать все, что хотите.
Как вернуть нуль при инициализации?
Я хочу:
obj = Foo.new(0) # => nil or false
Это не работает:
class Foo def initialize(val) return nil if val == 0 end end
Я знаю в C/С++/Java/С#, мы не можем вернуть значение в конструкторе.
Но мне интересно, возможно ли это в Ruby.
В Ruby нет такой конструкции, как конструктор. Конструкторы не нужны на хорошо продуманном языке. В Ruby существуют только методы и, конечно, методы могут возвращать значения.
Проблема, которую вы видите, просто заключается в том, что вы хотите изменить возвращаемое значение одного метода, но вы переопределяете другой метод. Конечно, это не работает. Если вы хотите изменить возвращаемое значение метода bar
, вы должны переопределить bar
, а не какой-либо другой метод.
Если вы хотите изменить поведение Foo::new
, вы должны изменить Foo::new
:
class Foo
def self.new(val)
return nil if val.zero?
super
end
end
Обратите внимание, что это действительно плохая идея, поскольку она нарушает контракт new
, который должен возвращать полностью инициализированный, полностью функционирующий экземпляр класса.
Существуют важные различия между этими двумя методами.
new
- это метод класса, который обычно создает экземпляр класса (это касается сложного материала, такого как выделение памяти, из которой Ruby защищает вас, поэтому вам не нужно слишком загрязняться).
Затем initialize
, метод экземпляра, указывает объекту установить его внутреннее состояние в соответствии с запрошенными параметрами.
Любой из них может быть переопределен в зависимости от того, что вы хотите. Например, Foo.new
может фактически создать и вернуть экземпляр FooSubclass
, если он должен быть достаточно умен, чтобы сделать это.
Однако часто лучше делегировать примеры использования, подобные этим, другим методам класса, которые более ясны в отношении того, что они делают, например Foo.relating_to(bar)
. Преодолевая ожидания других людей о том, какие методы, подобные new
, должны делать, будут путать людей больше, чем это поможет им в долгосрочной перспективе.
В качестве примера рассмотрим реализацию Singleton
, модуля, который позволяет использовать только один экземпляр определенного класса. Это делает метод new
закрытым и предоставляет метод instance
, который либо возвращает существующий экземпляр объекта, либо вызывает new
, если он еще не создан.
Вы можете что-то вроде этого:
class Foo
def self.init(val)
new(val) unless val == 0
end
def initialize(val)
#...
end
end
Пример использования:
obj = Foo.init(0)
=> nil
obj = Foo.init(5)
=> #<Foo:0x00000002970a98>
Желание сделать
class Foo
def initialize(val)
return nil if val == 0
end
end
сделает для непоследовательного кода.
Если у вас
class Foo
def initialize(val)
return nil if val == 0
@val = val
@bar = 42
end
end
что бы вы хотели вернуть, если вы сделали Foo.new(1)
? Вы хотите 42
(возвращаемое значение для Foo#initialize
) или объект foo
? Если вы хотите foo
объект для Foo.new(1)
, то почему вы ожидаете, что return nil
сделает Foo.new(0)
return nil?
Классы в Ruby являются первоклассными объектами - каждый из них является экземпляром класса Class. Когда новый класс определен (обычно с использованием класса Name... end), объект типа Class создается и присваивается константе (в этом случае имя.). Когда Name.new вызывается для создания нового объекта, новый метод класса в классе запускается по умолчанию, который, в свою очередь, вызывает выделение для выделения памяти для объекта, прежде чем, наконец, вызвать метод инициализации нового объекта. Фазы построения и инициализации объекта являются раздельными, и оба могут быть перегружены. Конструкция выполняется с помощью метода нового класса, инициализация выполняется с помощью метода экземпляра initialize. initialize не является конструктором!
Решается путем простого создания переменной объекта следующим образом:
class Foo
def initialize(val)
@val = val
return nil if @val == 0
end
end
obj = Foo.new(0)
Output:-
=>#<Foo:0x1243b8 @val=0>
Выход зависит от разных компьютеров.