Подтвердить что ты не робот

В Ruby, какие отношения между "новым" и "инициализировать"? Как вернуть нуль при инициализации?

Я хочу:

obj = Foo.new(0)  # => nil or false

Это не работает:

class Foo
  def initialize(val)
    return nil if val == 0
  end
end

Я знаю в C/С++/Java/С#, мы не можем вернуть значение в конструкторе.

Но мне интересно, возможно ли это в Ruby.

4b9b3361

Ответ 1

В 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, который должен возвращать полностью инициализированный, полностью функционирующий экземпляр класса.

Ответ 2

Существуют важные различия между этими двумя методами.

new - это метод класса, который обычно создает экземпляр класса (это касается сложного материала, такого как выделение памяти, из которой Ruby защищает вас, поэтому вам не нужно слишком загрязняться).

Затем initialize, метод экземпляра, указывает объекту установить его внутреннее состояние в соответствии с запрошенными параметрами.

Любой из них может быть переопределен в зависимости от того, что вы хотите. Например, Foo.new может фактически создать и вернуть экземпляр FooSubclass, если он должен быть достаточно умен, чтобы сделать это.

Однако часто лучше делегировать примеры использования, подобные этим, другим методам класса, которые более ясны в отношении того, что они делают, например Foo.relating_to(bar). Преодолевая ожидания других людей о том, какие методы, подобные new, должны делать, будут путать людей больше, чем это поможет им в долгосрочной перспективе.

В качестве примера рассмотрим реализацию Singleton, модуля, который позволяет использовать только один экземпляр определенного класса. Это делает метод new закрытым и предоставляет метод instance, который либо возвращает существующий экземпляр объекта, либо вызывает new, если он еще не создан.

Ответ 3

Вы можете что-то вроде этого:

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>

Ответ 4

Желание сделать

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?

Ответ 5

Классы в Ruby являются первоклассными объектами - каждый из них является экземпляром класса Class. Когда новый класс определен (обычно с использованием класса Name... end), объект типа Class создается и присваивается константе (в этом случае имя.). Когда Name.new вызывается для создания нового объекта, новый метод класса в классе запускается по умолчанию, который, в свою очередь, вызывает выделение для выделения памяти для объекта, прежде чем, наконец, вызвать метод инициализации нового объекта. Фазы построения и инициализации объекта являются раздельными, и оба могут быть перегружены. Конструкция выполняется с помощью метода нового класса, инициализация выполняется с помощью метода экземпляра initialize. initialize не является конструктором!

Ответ 6

Решается путем простого создания переменной объекта следующим образом:

class Foo
   def initialize(val)
       @val = val
       return nil if @val == 0
   end
end
obj = Foo.new(0)

Output:-
=>#<Foo:0x1243b8 @val=0>

Выход зависит от разных компьютеров.