Ruby:在块中使用self?

时间:2014-07-03 13:26:04

标签: ruby

简短问题:当调用对象“a”的方法并将其传递给块时,我可以从该块中访问“a”吗?

示例:假设我有一个数组“单词”,我首先要从中删除所有“坏”单词(使用函数确定),然后找到剩下的单词中最常见的单词。我可以用两行来完成:

temp_words = words.reject{|w| word_is_bad(w)}
puts temp_words.max{|w| temp_words.count(w)}

但是,我希望避免创建一个名为“temp_words”的新变量,并在一行中执行所有操作,如下所示:

words.reject{|w| word_is_bad(w)}.max{|w| self.count(w)}

即使我相信我的意图很明确,代码也会失败,因为“self”并不是指在调用reject之后生成的临时数组,而是指程序的主对象。

2 个答案:

答案 0 :(得分:3)

如果你想坚持自己的方式,你可以写:

words.reject{|w| word_is_bad(w)}.instance_eval{max_by{|w| count(w)}}

但更好,更受欢迎的方法是:

words.reject{|w| word_is_bad(w)}.group_by{|w| w}.max_by{|_, a| a.length}.first

答案 1 :(得分:3)

简短的回答是否定的,不是没有使用instance_eval或类似的东西。

你真的不需要链接块。总是可以这样写:

 words.max_by {|w| word_is_bad(w) ? -1 : words.count(w) }

(旁注,我想你可能想要max_by而不是max)

如果您发现自己必须聪明地使用一个衬垫来表达您的逻辑,那么在类中封装您需要的内容可能是有意义的。考虑这个简单的例子:

class Words < Array
  def self.is_bad(word)
    foo
  end

  def good
    reject {|w| Word.is_bad(w) }
  end
end

这将允许你写:

words = Words.new(["foo", "bar", "baz"])
words.good.max_by {|word| words.count(word) }

更具表现力并回避问题。

更进一步:

def max_good
  good.max_by {|word| count(word) }
end

你可以简单地写words.max_good