Ruby: Как определить, сколько переменных присваивается вызывающим методом - PullRequest
1 голос
/ 26 сентября 2019

Я бы хотел, чтобы мой метод изменил то, что он возвращает, в зависимости от того, сколько переменных назначено вызывающей стороной.Есть ли способ запросить это в методе?Или есть способ закодировать возвращаемое значение 2, чтобы второе значение было проигнорировано, если назначение назначения не указано?Спасибо!- Майлз

def foo
  if <two-vars-being-assigned>
    return [:bar, :baz] 
  else
    return :bar
  end
end

x, y = foo

# I want x to get :bar, not [:bar, :baz]
x = foo

Ответы [ 3 ]

5 голосов
/ 26 сентября 2019

Если бы вы действительно хотели, вы могли бы вернуть объект, который отвечает на to_ary.Вы можете даже обезопасить Symbol в вашем примере методом to_ary.

Но ... НЕТ.Просто НЕТ.

class Symbol
  def to_ary
    [:bar, :baz]
  end
end

def foo
  :bar
end

a = foo
a #=> :bar

b, c = foo
b #=> :bar
c #=> :baz

Какой бы тип объекта вы не возвращали, он будет нарушать Принцип Единой Ответственности , поскольку он действует и как и любое предполагаемое возвращаемое значениедействовать как и как прокси для разделения себя на два возвращаемых значения.

Просто ... НЕТ.Шутки в сторону.NO.

3 голосов
/ 26 сентября 2019

Я бы сказал, что это невозможно.Когда вы вызываете x, y = foo, тогда foo вычисляется первым и, следовательно, запускается и возвращается до выполнения назначения.Кроме того, я не вижу простого и разумного способа заставить метод узнать структуру кода в том месте, из которого он был вызван.

Почему бы вам просто не обработать это в том месте, в котором вы вызываете этот метод?:

def foo
  [:bar, :baz] 
end

x, y = foo
x = foo.first
1 голос
/ 26 сентября 2019

То, что происходит с возвращаемым значением, явно выходит за рамки метода.Вы не должны пытаться обнаружить, что там происходит.

Очевидное решение состоит в том, чтобы решить это на стороне вызывающего, например, с помощью:

def foo
  [:bar, :baz]
end

x, = foo

# or more specific

x, _ = foo

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

def foo
  yield :bar, :baz
end

foo do |x|
  p x: x
  # prints {:x=>:bar}
end

foo do |x, y|
  p x: x, y: y
  # prints {:x=>:bar, :y=>:baz}
end

Если условие важно, вы можете проверить arity:

def foo(&block)
  if block.arity == 2
    yield :bar, :baz
  else
    yield :bar
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...