Ruby 如何使用if..else块的结果分配变量?
我和一位同事就在if..else块中分配变量的最佳方法进行了争论。他的原始代码是:Ruby 如何使用if..else块的结果分配变量?,ruby,coding-style,Ruby,Coding Style,我和一位同事就在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 = Pr
@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
对齐,这会让我的大脑更容易解析它 在我看来,第二个版本对于典型的程序员来说更具可读性。我不是一个喜欢ruby的人,所以我没有意识到if/else会返回一个值。。。。因此,以我为例(是的,这是我的观点:D),第二个似乎是一个不错的选择。如果使用三元,则第一个,如果不使用,则第二个
第一个命令几乎无法读取。我也不是Ruby人,但第二个命令的范围会立即响起警钟,该变量会在if块结束后可用吗?作为Ruby程序员,我发现第一个更清楚。它清楚地表明,整个表达式是一个赋值,根据某种逻辑确定赋值的对象,并减少了重复。对于那些不习惯所有语言都是表达式的人来说,这看起来很奇怪,但在我看来,为不懂这种语言的人编写代码并不是那么重要的目标,除非他们特别是你的目标用户。否则,人们应该对它略知一二 我也同意您可以通过缩进整个if表达式使其在视觉上位于作业右侧,从而使其读得更清楚。它完全是审美的,但我认为这使它更容易浏览,甚至对于不熟悉该语言的人来说也应该更清晰
作为旁白:这种
,如果
不是Ruby独有的。它存在于所有的Lisp(公共Lisp、Scheme、Clojure等)、Scala、所有的MLs(F#、OCaml、SML)、Haskell、Erlang甚至Ruby的直接前身Smalltalk中。这在基于C(C++、Java、C#、Objective-C)的语言中并不常见,这是大多数人使用的语言。我想说,对于不熟悉ruby结构的人来说,第二个版本更容易阅读。那就这么办吧!另一方面,第一次施工更加干燥
当我看得再长一点时,我发现第一个解决方案更具吸引力。我是一名ruby程序员,但我之前没有使用过它。当然,我会开始的 封装
@products = get_products
def get_products
if params[:category]
Category.find(params[:category]).products
else
Product.all
end
end
我不喜欢你在第一个块中使用空格。是的,我是一个PythOnista,但是我相信当我说第一个可能在其他代码的中间看起来很混乱时,我可以做出一个公平的观点,也许在其他<代码>如果 那么
@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]
…但如果
产品,这是一个坏主意。所有的实际上都是这样一个函数,可以对其进行不必要的计算。假设您的模型如下所示:
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]}} : {})
或者,您可以使用性感的、懒散加载的功能:
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
是另一种选择,它既避免重复@产品
,又使if
与else
保持一致,这只是另一种方法:
category = Category.find(params[:category]) if params[:category]
@products = category ? category.products : Product.all
如果你正在浏览代码,我会说第二个代码块(你的),肯定是我发现最容易快速理解的代码块
您好友的代码很好,但正如bp指出的那样,缩进在这个意义上有很大的不同。作为中语法的替代方案,我建议:
@products =
if params[:category]
Category.find(params[:category]).products
else
Product.all
end
我认为这有两个好处:
统一缩进:每一级逻辑嵌套都缩进两个空格(好吧,也许这只是一个品味问题)
水平紧凑性:较长的变量名不会将缩进的代码推过80(或任何)列标记
它确实需要额外的一行代码,这通常是我不喜欢的,但在这种情况下,用垂直极简主义来交换水平极简主义似乎是值得的
免责声明:这是我自己独特的方法,我不知道它在Ruby社区的其他地方使用到了什么程度
编辑:我应该提到的是,它也与此类似。我确实认为有一些缩进是有帮助的。我希望这足以证明将此作为一个单独的答案是合理的。另一种方法是使用块将其封装起来
@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
这是重写后的代码所不能做到的,而且它是正确对齐的。我不喜欢在第一个块中使用括号。是的,我是一个LISP用户,但是我相信当我说第一个可能在其他代码的中间看起来很混乱时,我可以做出一个公平的观点,也许在其他<代码> > Bug。
那么
@products = (if (params[:category])
((Category.find params[:category]).
products)
else
(Product all)
end
)
(^开玩笑,加剧问题)我认为最好的代码是:
@products = Category.find(params[:category])&.products.presence || Product.all
反查找后的“&”确保“产品”方法不会评估类别是否为零
这也可以使用三元运算符(?:
)用一行代码重写,但让我们假设产品分配长度超过100个字符,不能放在一行中
让我们假装不这样做——因为在许多情况下,优化变量名和长度条件复杂度以使包含条件的赋值适合于一行,这对可读性是有好处的
但是,不要使用三元运算符(这是一个很难读取的运算符),而是使用if…then…else
。然后
@products ||= begin
if params[:category]
Category.find(params[:category]).products
else
Product.all
end
end
@products = (if (params[:category])
((Category.find params[:category]).
products)
else
(Product all)
end
)
@products = Category.find(params[:category])&.products.presence || Product.all
cat = params[:category]
@products = if cat then Category.find(cat).products else Product.all end