Общий способ заменить объект в своем собственном методе - PullRequest
5 голосов
/ 03 февраля 2012

Со строками можно сделать это:

a = "hello"
a.upcase!
p a #=> "HELLO"

Но как бы я написал свой собственный метод, подобный этому?

Что-то вроде (хотя это, очевидно, не работает):

class MyClass
  def positify!
    self = [0, self].max
  end
end

Я знаю, что есть некоторые приемы, которые можно использовать в String, но что, если я пытаюсь сделать что-то подобное для Object?

Ответы [ 4 ]

7 голосов
/ 03 февраля 2012

Многие классы являются неизменяемыми (например, Numeric, Symbol, ...), поэтому не имеют метода, позволяющего изменить их значение.

С другой стороны, любой Object может иметьпеременные экземпляра и их можно изменять.

Существует простой способ делегировать поведение известному объекту (скажем, 42) и впоследствии иметь возможность изменить другой объект, используя SimpleDelegator.В приведенном ниже примере quacks_like_an_int ведет себя как Integer:

require 'delegate'
quacks_like_an_int = SimpleDelegator.new(42)
quacks_like_an_int.round(-1) # => 40
quacks_like_an_int.__setobj__(666)
quacks_like_an_int.round(-1) # => 670

Вы также можете использовать его для разработки класса, например:

require 'delegate'
class MutableInteger < SimpleDelegator
  def plus_plus!
    __setobj__(self + 1)
    self
  end

  def positify!
    __setobj__(0) if self < 0
    self
  end
end

i = MutableInteger.new(-42)
i.plus_plus! # => -41
i.positify! # => 0
4 голосов
/ 03 февраля 2012

Ну, метод upcase! не меняет идентичность объекта, он только меняет его внутреннюю структуру (s.object_id == s.upcase!.object_id).

С другой стороны, числа являются неизменяемыми объектами, и поэтому вы не можете изменить их значение без изменения их идентичности. AFAIK, у объекта нет возможности самостоятельно изменить свою идентичность, но, конечно, вы можете реализовать метод positify!, который изменяет свойства своего объекта - и этот будет аналогом того, что upcase! делает для строк.

2 голосов
/ 03 февраля 2012

Вы не можете изменить себя, чтобы указывать на что-либо, кроме текущего объекта.Вы можете вносить изменения в переменные экземпляра, например, в строку case, которая изменяет нижележащие символы в верхний регистр.

Как указано в этом ответе: Ruby и изменение self для экземпляра Float

Здесь упоминается трюк, который является обходным путем, который заключается в написании вашего класса как обертки вокруг другого объекта.Тогда ваш класс-оболочка может заменить обернутый объект по желанию.Хотя я не решаюсь сказать, что это хорошая идея.

2 голосов
/ 03 февраля 2012

Назначение или привязка локальных переменных (с помощью оператора =) встроено в основной язык, и его невозможно переопределить или настроить.Вы можете запустить препроцессор над своим кодом Ruby, который, однако, преобразует ваш собственный настраиваемый синтаксис в правильный Ruby.Вы также можете передать Binding в пользовательский метод, который может динамически переопределять переменные.Это не даст желаемого эффекта.

Поймите, что self = никогда не сработает, потому что когда вы говорите a = "string"; a = "another string", вы не модифицируете никакие объекты;Вы привязываете локальную переменную к другому объекту.Внутри вашего пользовательского метода вы находитесь в другой области видимости, и любые локальные переменные, которые вы связываете, будут существовать только в этой области ;это не повлияет на область, из которой вы вызвали метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...