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

Как вы назначаете переменную с результатом if ifelse?

У меня был аргумент с коллегой о том, как лучше назначить переменную в блоке if..else. Его оргинальный код:

@products = if params[:category]
  Category.find(params[:category]).products
else
  Product.all
end

Я переписал его так:

if params[:category]
  @products = Category.find(params[:category]).products
else
  @products = Product.all
end

Это также можно было бы переписать с помощью однострочного интерфейса с помощью оператора ternery (?:), но предположим, что назначение продукта длиннее 100 символов и не может помещаться в одну строку.

Какой из двух яснее вам? Первое решение занимает немного меньше места, но я думал, что объявление переменной и присвоение ей трех строк после этого может быть более подверженным ошибкам. Мне также нравится видеть, что мои if и else выровнены, облегчает мой мозг анализировать его!

4b9b3361

Ответ 1

В качестве альтернативы синтаксису в badp answer, я хотел бы предложить:

@products = 
  if params[:category]
    Category.find(params[:category]).products
  else
    Product.all
  end

Я утверждаю, что это имеет два преимущества:

  • Равномерное отступление: каждый уровень логического вложения отступен ровно двумя пробелами (ОК, может быть, это только вопрос вкуса).
  • Горизонтальная компактность:. Более длинное имя переменной не будет вытолкнуть отступы после отметки столбца 80 (или любого другого)

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

Отказ от ответственности: это мой собственный индивидуальный подход, и я не знаю, насколько он используется в другом месте сообщества Ruby.

Изменить: Я бы сказал, что ответ matsadler также похож на этот. Я действительно думаю, что некоторые отступы полезны. Я надеюсь, что этого достаточно, чтобы оправдать принятие этого отдельного ответа.

Ответ 2

Как программист Ruby, я нахожу первый яснее. Это дает понять, что все выражение является назначением с назначенной вещью, определенной на основе некоторой логики, и это уменьшает дублирование. Это будет выглядеть странно для людей, которые не привыкли к языкам, где все является выражением, но писать свой код для людей, которые не знают язык, не так важны для ИМО, если они специально не являются вашими целевыми пользователями. В противном случае следует ожидать, что у людей будет знакомое знакомство.

Я также согласен с предложением bp, чтобы вы могли сделать его более понятным, отделив все if-выражение, чтобы он был визуально справа от задания, Это совершенно эстетично, но я думаю, что это делает его более легко скимным и должно быть понятнее даже кому-то незнакомую с языком.

Как и в стороне: Этот тип if вовсе не уникален для Ruby. Он существует во всех Lisps (Common Lisp, Scheme, Clojure и т.д.), Scala, все ML (F #, OCaml, SML), Haskell, Erlang и даже прямой предшественник Ruby, Smalltalk. Это просто не распространено в языках, основанных на C (С++, Java, С#, Objective-C), что и используется большинством людей.

Ответ 3

Мне не нравится использование пробелов в вашем первом блоке. Да, я Pythonista, но я считаю, что я считаю, что первый может показаться запутанным в середине другого кода, возможно, вокруг других блоков if.

Как насчет...

@products = if params[:category] Category.find(params[:category]).products
            else                 Product.all
            end

@products = if params[:category]
              Category.find(params[:category]).products
            else                
              Product.all
            end

Вы также можете попробовать...

@products = Product.all #unless a category is specified:
@products = Category.find(params[:category]).products if params[:category]

... но это плохая идея, если Product.all на самом деле является функцией, которая затем может быть бесполезной.

Ответ 4

герметизация...

@products = get_products

def get_products
  if params[:category]
    Category.find(params[:category]).products
  else
    Product.all
  end
end

Ответ 5

Еще один подход:

category = Category.find(params[:category]) if params[:category]
@products = category ? category.products : Product.all

Ответ 6

Еще один подход - использовать блок для его завершения.

@products = begin
  if params[:category]
    Category.find(params[:category]).products
  else
    Product.all
  end
end

который решает проблему присвоения. Хотя, слишком много строк для такого "сложного" кода. Этот подход был бы полезен в том случае, если мы хотели бы инициализировать переменную только один раз:

@products ||= begin
  if params[:category]
    Category.find(params[:category]).products
  else
    Product.all
  end
end

Это то, что вы не можете сделать с перезаписанным кодом и правильно выровнено.

Ответ 7

Предполагая, что ваши модели выглядят следующим образом:

class Category < ActiveRecord::Base
  has_many :products
end
class Product < ActiveRecord::Base
  belongs_to :category
end

вы могли бы сделать что-то еще более сумасшедшее, например:

#assuming params[:category] is an id
@products = Product.all( params[:category] ? {:conditions => { :category_id => params[:category]}} : {})

Или вы можете использовать сексуальную, лениво загруженную named_scope:

class Product < ActiveRecord::Base
  ...

  #again assuming category_id exists
  named_scope :all_by_category, lambda do |cat_id|
    if cat_id
      {:conditions => {:category_id => cat_id}}
    end
  end

  #if params[:category] is a name, and there is a has and belongs to many
  named_scope :all_by_category, lambda do |cat_name|
    if cat_name
      {:joins => :categories, :conditions => ["categories.name = ?",cat_name]}
    end
  end
  ...
end

используется как

@products = Product.all_by_category params[:category]

Ответ 8

@products =
if params[:category]
  Category.find(params[:category]).products
else
  Product.all
end

Это еще один вариант: он избегает повторения @products и сохраняет if в соответствии с else.

Ответ 9

Сначала, если вы используете тройной, второй, если нет.

Первый из них почти невозможно прочитать.

Ответ 10

Я тоже не человек Ruby, но Alarm Bells мгновенно звонит в область второй команды, будет ли эта переменная даже доступна после завершения вашего if-блока?

Ответ 11

Я бы сказал, что вторая версия более читаема для людей, не знакомых с этой структурой в рубине. Так что + за это! С другой стороны, первая конструкция более сухая.

Как я смотрю на это немного дольше, я считаю первое решение более привлекательным. Я программист на рубине, но раньше не использовал его. Конечно, я начну!

Ответ 12

Мне кажется, что второй будет более понятным для типичного программиста. Я не рубиновый парень, поэтому я не понимал, что if/else возвращает значение... Итак, чтобы взять меня в качестве примера (и да, это моя перспектива: D), второй выглядит как хороший выбор.

Ответ 13

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

Ваш код приятеля в порядке, но отступ, как указывал БП, делает мир различий в этом смысле.

Ответ 14

Мне не нравится использование скобок в вашем первом блоке. Да, я пользователь LISP, но я считаю, что я считаю, что первое может показаться запутанным в середине другого кода, возможно, вокруг других блоков if.

Как насчет...

@products = (if (params[:category])
        ((Category.find params[:category]).
            products)
    else
        (Product all)
    end
)

(^ Язык в щеке, чтобы усугубить проблемы с @badp answer)