为什么单个`=`在`if`语句中工作?

此代码作为示例提供,用于与devise和OmniAuth一起使用,它可以在我的项目中使用 。

class User < ActiveRecord::Base def self.new_with_session(params, session) super.tap do |user| if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"] user.email = data["email"] if user.email.blank? end end end end 

我不知道为什么它是一个单一的等号作为一个双等号,我认为这对于if -statements是必要的。 我的IDE“intelliJ IDEA”同意我的担忧。

if语句有效的唯一必要条件是布尔表达式。 在这种情况下,因为=返回赋值的结果,实际测试的是session["devise.facebook_data"]的虚假性session["devise.facebook_data"]

IntelliJ对于这样的代码抱怨很有意义,因为如果不了解Ruby的一两件事就难以阅读。 建议是将其移至明确的赋值语句中。 这具有额外的好处,即对其进行两次干燥。

 class User < ActiveRecord::Base def self.new_with_session(params, session) super.tap do |user| data = session["devise.facebook_data"] if data && data["extra"]["raw_info"] user.email = data["email"] if user.email.blank? end end end end 

在Ruby中,单个等号用于赋值 。 表达方式

 data = session["devise.facebook_data"] 

session["devise.facebook_data"]的评估结果分配给名为data的局部变量。

如果session哈希没有"devise.facebook_data"键,它将返回nildata将被分配为nil 。 赋值评估为分配的值,因此赋值也将计算为nilnil在布尔上下文中被认为是假的,因此不会评估&&的右操作数。 这样,你不会得到一个NoMethodError试图调用nil["extra"]["raw_info"]

如果session散列确实具有"devise.facebook_data"键,则data将被设置为与其关联的值。 除nilfalse之外的任何值都被认为是真实的,因此将评估&&运算符的右侧操作数。

如果条件是真实的,则将评估then子句,该子句使用条件中指定的data变量。


注意:我相信也可以在&&运算符的右侧使用data变量,即条件可以这样读取:

 if data = session["devise.facebook_data"] && data["extra"]["raw_info"] 

但我必须检查一下。

赋值运算符( = )返回指定的值,然后由if 。 在ruby中,只有falsenil被认为是false 。 其他所有内容在布尔上下文中评估为true (如if )。

与Java不同,Ruby不关心条件中的类型。 只要该值既不是零也不是假,那么它将通过。

在您的示例中,您实际上区分了nil:if conditionnal确保数据实际存在且不是nil,因此我们可以使用它,假设它是一个哈希值。 这是Ruby中的常见模式。