Как вы назначаете переменную с результатом 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
выровнены, облегчает мой мозг анализировать его!
Ответы
Ответ 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)