Я хочу:
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>
Выход зависит от разных компьютеров.