有没有一个Ruby或者Ruby-ism的方法可以实现not_nil?与nil相反的方法?

102

我不太熟悉 Ruby,所以我的代码感觉“丑陋”而且不符合惯用语法:

def logged_in?
  !user.nil?
end
我更喜欢像这样的东西
def logged_in?
  user.not_nil?
end

但是找不到与 nil? 相反的方法。

7个回答

51

你似乎过于关注布尔值。

def logged_in?
  user
end
如果用户为空,则logged_in?将返回“falsey”值。否则,它将返回一个对象。在Ruby中,我们不需要返回true或false,因为我们有像JavaScript中的“truthy”和“falsey”值。
更新: 如果您使用Rails,可以通过使用present?方法使其读起来更加清晰:
def logged_in?
  user.present?
end

1
以一个以 ? 结尾的方法为例,我们期望它返回一个布尔值。!!value 是将任何东西转换为布尔值的经典方式。虽然不完全相同,但在这种情况下,RoR 中的 Object#present? 也是一个不错的选择。 - tokland
这在 Ruby 2.4 中实际上会出现错误:Path! [43] (pry) #ReactOnRails::AssetsPrecompile: 0> assets_path.blank? true [44] (pry) #ReactOnRails::AssetsPrecompile:0> assets_path.to_s "/var/folders/rp/_k99k0pn0rsb4d3lm9l3dnjh0000gn/T/d20170603-96466-zk7di7" [45] (pry) #ReactOnRails::AssetsPrecompile:0> assets_path.present?false [46] (pry) #ReactOnRails::AssetsPrecompile:0> assets_path.nil?false - justingordon
1
虽然这解决了特定的问题,但 .present? 不是 .nil? 的相反。事实上,它是 .blank? 的相反。 - Juan Ignacio Marquez
我被这个答案误导了,导致了一个错误。我使用了array.present?,当数组不为空时它返回了false,而实际上数组是空的。所以实际上array.nil?array.present?都返回了false。所以array.present?并不是array.nil?的相反,因为相反意味着两者不能同时为真或假。 - undefined
最后两个评论是公正的,.present?并不真正是.nil?的相反,这正是问题标题所要求的。问题本身明确表示OP正在寻找一种确定变量是否具有非空值的方法,因此.present?是推荐的,尽管它不是标题指定的内容。这不是我今天回答问题的语气和格式,但这是一个13年前的回答。我感谢你的纠正。 - undefined

49

我在原始帖子中添加了一个标签,表明我确实正在使用Rails,因此user.present?是存在的。据我所知,这确实是nil的正好相反吗?因此在这个上下文中(一个Rails项目),这正是我需要的。 - berkes
56
注意:present? 要求一个非空字符串。! "".nil? 返回 true,但是 "".present? 返回 false。 - lambshaanxy
10
警告2:我还要指出,!!user 不能区分user为nil和user为false的情况;双重非使用混淆了这两种情况。因此,如果你真的想确定一个对象不是nil(意思是,它是:true、false、0、“”等任何东西,除了nil),你需要使用berkes不喜欢的“丑陋”方法或者@Tempus在下面提出的monkeypatch。当然,在这种情况下,不需要not nil(Rails中的用户),在我看来,Samo所采取的方法最不难看。 - likethesky
20
false.present? == false !false.nil? == true - Dudo
4
这个回答完全没有回答所提出的问题。它只是针对这个特定的实现问题做出了回答。 - Ekkstein
5
这个答案是不正确的。false.nil? 是假的,而 false.present? 也同样是假的! - Mike

36

注意其他回答中提出present?作为您问题的答案。

present?在Rails中是blank?的反义词。

present?用于检查是否存在有意义的值,以下情况将无法通过present?检查:

"".present? # false
"    ".present? # false
[].present? # false
false.present? # false
YourActiveRecordModel.where("false = true").present? # false

当使用!nil?检查时,其结果为:

!"".nil? # true
!"    ".nil? # true
![].nil? # true
!false.nil? # true
!YourActiveRecordModel.where("false = true").nil? # true

nil?检查对象是否实际上为nil。其他任何内容:空字符串、0false等都不是nil

present?非常有用,但绝对不是nil?的相反。混淆这两个可能会导致意想不到的错误。

对于您的用例,present?将起作用,但始终要注意区别。


应该包含在被接受的答案中。false.blank? 不同于 false.nil? - Yason
present?会查询你的数据库,而nil?则不会,使用时要小心。 - Tony

21

也许这可能是一种方法:

class Object
  def not_nil?
    !nil?
  end
end

好主意。我理解这表示 Ruby 中没有 not_nil? 方法。但是,这应该不是 !nil?,而是 !self.nil?,因为 self 是隐式的吗? - berkes
3
不需要自己。这将会被暗示。 - Geo
当从实例方法(或访问器,它们实际上只是方法)读取时,self是隐含的。在设置值时,在Ruby检查具有相同名称的setter方法的类实例之前,将创建一个局部变量以供该方法使用。通用规则:如果您有一个名为xxx的attr_accessor,请使用“self.xxx = 3”(设置值)或“temp = xxx”(读取值)。使用“xxx = 3”不会更新访问器,只会在方法范围内创建一个新变量。 - A Fader Darkly

17

我可以建议在nil?方法的结果上使用类似Ruby中的方法。

def logged_in?
  user.nil?.!
end

这个东西太深奥了,以至于RubyMine IDE会将其标记为错误。 ;-)


4

您可以直接使用以下代码:

if object
  p "object exists"
else
  p "object does not exist"
end

这不仅适用于nil,还适用于false等情况,因此您应该测试以查看它在您的用例中是否有效。


2
我查看此问题是为了寻找一个对象方法,以便我可以使用Symbol#to_proc简写而不是块;我认为arr.find(&:not_nil?)arr.find { |e| !e.nil? }更易读。
我找到的方法是Object#itself。在我的用法中,我想要找到哈希中键为name的值,在某些情况下,该键被错误地大写为Name。这个一行代码如下:
# Extract values for several possible keys 
#   and find the first non-nil one
["Name", "name"].map { |k| my_hash[k] }.find(&:itself)

正如其他回答所指出的那样,如果您正在测试布尔值,这种方法将会失败。

最初的回答:原始答案


那个跟 my_hash.values_at("Name", "name").find 有什么不同? - berkes
完全一样。在我的原始“map”中,我有其他逻辑,但为了简单起见,在这个例子中我将其删除了,因此它与“values_at”是可互换的。重要的部分是传递给“find”的内容。 - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接