ruby -你能用lambda或functors迭代一组声明的函数吗?

46qrfjad  于 2023-04-05  发布在  Ruby
关注(0)|答案(2)|浏览(84)

在Ruby中,如果我有n个函数:

def a
    puts "a"
end

def b
    puts "b"
end

有没有什么方法可以像

[a,b].each do |x|
    puts "running #{x.name}
    run a
end

我的一个想法是,我可以注册一个函子数组或其他东西,或者lambda可以帮助?
谢谢你的帮助,凯文

lawou6xi

lawou6xi1#

Call Object#send on a Array of Symbols

在Ruby中,def关键字定义了一个对象方法而不是函数。Ruby中最接近函数的是块、procs和lambda表达式,但“函数”在Ruby中并不是真正的一流概念。
方法存在于一个对象上,但是如果你在顶级命名空间中声明它们(例如在类的外部),那么它们会被附加到一个特殊的顶级绑定中,这个绑定的作用 * 有点 * 像一个全局命名空间。这不是,真的,但是当试图从其他语言中推理Ruby时,这是一个有用的类比。
此外,当你定义一个方法时,Ruby会为该方法返回一个Symbol。你可以在定义方法时在交互式REPL(如irb)中看到这一点,因为Ruby在定义方法时会返回一个Symbol。虽然有一些方法可以以String的形式调用方法名,但Ruby在内部将方法和类名存储为Symbol对象,所以这就是我将要演示的内容。例如:

def a
    puts "a"
end
#=> :a

有了这些知识,就很容易迭代一组存储为Symbol对象数组的方法,并使用Object#send调用它们中的每一个。例如:

def a
    p "a"
end

def b
    p "b"
end

[:a, :b].each { send _1 }
#=> [:a, :b]

虽然它为每个方法返回Symbol,但它也会将您期望的字符打印到终端:
“一个”
“B”
请注意,#puts总是返回nil,所以当你想 * 返回 * 通过迭代你的集合而不是简单地将它们发送到终端而生成的值时,使用内核#p更有意义。如果你宁愿返回[nil, nil],那么继续使用#puts代替。
此外,使用#map而不是#each与Kernel#p一起使用,每次迭代都会返回一个字母而不是Symbol,所以要注意区别。期望一个而得到以下结果可能会令人困惑:

[:a, :b].map { send _1 }
# => ["a", "b"]

这是因为#each返回原始Array,而#map返回在每个元素上Map块的结果。它们非常相似,但如果不小心,细微的差异可能会让你绊倒。

保留原有语义

如果你真的想保持你原来的语义,那么就这样称呼它:

["a", "b"].map do |x|
    puts "running method #{x}"
    send x
end

这不太符合习惯,而且可能会让人感到困惑,因为你并没有真正使用字符或String对象,但无论你使用#each还是#map,都会得到一个String。尽管如此,它会打印并返回:

running method a
"a"
running method b
"b"
#=> ["a", "b"]

正如你所料

mm5n2pyu

mm5n2pyu2#

使用Lambda:

[
  -> () { p "a" },
  -> () { p "b" }
].each do
  |proc|
  proc.()
end

相关问题