Метод определения в Ruby с равными

Будучи новым для Ruby, у меня возникли проблемы с объяснением для себя поведения вокруг определений методов в Ruby.

Пример ниже...

class Foo
  def do_something(action)
    action.inspect
  end
  def do_something_else=action 
    action.inspect
  end
end

?> f.do_something("drive")
=> "\"drive\""

?> f.do_something_else=("drive")
=> "drive"

Первый пример является самоочевидным. То, что я пытаюсь понять, - это поведение второго примера. Кроме того, что выглядит как производящий строковый литерал, а другой - нет, что на самом деле происходит? Почему я должен использовать один над другим?

Ответ 1

Как правило, do_something является геттером, а do_something= - сеттер.

class Foo
  attr_accessor :bar
end

эквивалентно

class Foo
  def bar
    @bar
  end

  def bar=(value)
    @bar = value
  end
end

Чтобы ответить на ваш вопрос о различии в поведении, методы, заканчивающиеся на =, всегда возвращают правую часть выражения. В этом случае возврат action, а не action.inspect.

class Foo
  def do_something=(action)
    "stop"
  end
end

?> f = Foo.new
?> f.do_something=("drive")
=> "drive"

Ответ 2

Оба ваших метода на самом деле определяются и называются методами. Довольно много вещей в Ruby можно определить как методы, даже такие операторы, как +, -, * и /. Ruby позволяет использовать три специальных суффикса для обозначения. Я сам сделал эту фразу. То, что я подразумеваю под нотационными суффиксами, - это то, что в конце метода указывается, как этот метод должен работать.

Взрыва!

Первый нотационный суффикс !. Это указывает на то, что метод должен быть разрушительным, что означает, что он изменяет объект, на который он вызвал. Сравните выходные данные этих двух скриптов:

a = [1, 2, 3]
a.map { |x| x * x }
a

и

a = [1, 2, 3]
a.map! { |x| x * x }
a

Там между двумя сценариями разница в одном символе, но они действуют по-разному! Первый будет по-прежнему проходить через каждый элемент массива и выполнять операцию внутри блока, но объект в a по-прежнему будет тем же самым [1,2,3], с которого вы начали.

Во втором примере, однако, a в конце будет [1, 4, 9], потому что map! изменяет объект на месте!

Query

Второй нотационный суффикс ?, и это указывает, что метод используется для запроса объекта о чем-то и означает, что метод должен возвращать true, false или в некотором экстремальные обстоятельства, nil.

Теперь обратите внимание, что метод не должен возвращать true или false... это просто очень хорошо, если бы он это сделал!

Доказательство:

def a?
  true
end

def b?
  "moo"
end

Вызов a? вернет true, а вызов b? вернет "moo". Так вот, эти методы запросов. Методы, которые должны возвращать true или false, но иногда могут возвращать другие вещи, потому что некоторым разработчикам не нравятся другие разработчики.

Инкубационный!

СЕЙЧАС мы получаем мясо вашего (перефразируемого) вопроса: что означает = в конце метода?

Это обычно указывает, что метод собирается установить определенное значение, поскольку Erik уже обрисован до того, как я закончил написание этого эссе ответа.

Однако он может не устанавливать его так же, как методы запроса могут не возвращать true или false. Это просто соглашение.

Вы также можете вызвать этот метод setter:

foo.something_else="value"

Или (мой любимый):

foo.something_else = "value"

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

def foo?(*args)
  "moo"
end

>> foo?(:please, :oh, :please, :why, :"won't", :you, :use, :these, :arguments, :i, :got, :just, :for, :you, :question_mark?)
=> "moo"

Ruby поддерживает все три синтаксиса для методов setter, хотя очень редко можно увидеть тот, который вы использовали!

Хорошо, я надеюсь, что этот ответ был грубо воспитательным и теперь вы понимаете больше о Ruby. Наслаждайтесь!

Ответ 3

Вы не можете определить возвращаемое значение для методов присваивания. Возвращаемое значение всегда совпадает с переданным значением, так что цепочки присваивания (x = y = z = 3) всегда будут работать.

Как правило, вы должны опускать скобки при вызове метода, чтобы он вел себя как свойство:

my_value = f.do_something= "drive"

Ответ 4

def do_something_else=action 
  action.inspect
end

Это определяет метод setter, поэтому do_something_else выглядит так, как будто мы инициализируем атрибут. Таким образом, инициализированное значение передается непосредственно,