你能在 Ruby 中为 map(&:method) 语法提供参数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23695653/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can you supply arguments to the map(&:method) syntax in Ruby?
提问by Zack Xu
You're probably familiar with the following Ruby shorthand (ais an array):
您可能熟悉以下 Ruby 简写(a是一个数组):
a.map(&:method)
For example, try the following in irb:
例如,在 irb 中尝试以下操作:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
The syntax a.map(&:class)is a shorthand for a.map {|x| x.class}.
语法a.map(&:class)是a.map {|x| x.class}.
Read more about this syntax in "What does map(&:name) mean in Ruby?".
在“ map(&:name) 在 Ruby 中的含义是什么?”中阅读有关此语法的更多信息。
Through the syntax &:class, you're making a method call classfor each array element.
通过语法&:class,您可以class为每个数组元素进行方法调用。
My question is: can you supply arguments to the method call? And if so, how?
我的问题是:你能为方法调用提供参数吗?如果是这样,如何?
For example, how do you convert the following syntax
比如下面的语法怎么转换
a = [1,3,5,7,9]
a.map {|x| x + 2}
to the &:syntax?
在&:语法?
I'm not suggesting that the &:syntax is better.
I'm merely interested in the mechanics of using the &:syntax with arguments.
我并不是说&:语法更好。我只是对使用&:带参数的语法的机制感兴趣。
I assume you know that +is a method on Integer class. You can try the following in irb:
我假设你知道这+是一个 Integer 类的方法。您可以在 irb 中尝试以下操作:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
回答by Uri Agassi
You can create a simple patch on Symbollike this:
您可以Symbol像这样创建一个简单的补丁:
class Symbol
def with(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
Which will enable you to do not only this:
这将使您不仅可以做到这一点:
a = [1,3,5,7,9]
a.map(&:+.with(2))
# => [3, 5, 7, 9, 11]
But also a lot of other cool stuff, like passing multiple parameters:
还有很多其他很酷的东西,比如传递多个参数:
arr = ["abc", "babc", "great", "fruit"]
arr.map(&:center.with(20, '*'))
# => ["********abc*********", "********babc********", "*******great********", "*******fruit********"]
arr.map(&:[].with(1, 3))
# => ["bc", "abc", "rea", "rui"]
arr.map(&:[].with(/a(.*)/))
# => ["abc", "abc", "at", nil]
arr.map(&:[].with(/a(.*)/, 1))
# => ["bc", "bc", "t", nil]
And even work with inject, which passes two arguments to the block:
甚至使用inject,它将两个参数传递给块:
%w(abecd ab cd).inject(&:gsub.with('cde'))
# => "cdeeecde"
Or something super cool as passing [shorthand] blocks tothe shorthand block:
或者将 [速记] 块传递给速记块时非常酷的事情:
[['0', '1'], ['2', '3']].map(&:map.with(&:to_i))
# => [[0, 1], [2, 3]]
[%w(a b), %w(c d)].map(&:inject.with(&:+))
# => ["ab", "cd"]
[(1..5), (6..10)].map(&:map.with(&:*.with(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
Here is a conversation I had with @ArupRakshit explaining it further:
Can you supply arguments to the map(&:method) syntax in Ruby?
这是我与@ArupRakshit 进行的进一步解释的对话:
您能否为 Ruby 中的 map(&:method) 语法提供参数?
As @amcaplan suggested in the comment below, you could create a shorter syntax, if you rename the withmethod to call. In this case, ruby has a built in shortcut for this special method .().
正如@amcaplan 在下面的评论中建议的那样,如果将with方法重命名为call. 在这种情况下,ruby 为这个特殊方法提供了一个内置的快捷方式.()。
So you could use the above like this:
所以你可以像这样使用上面的:
class Symbol
def call(*args, &block)
->(caller, *rest) { caller.send(self, *rest, *args, &block) }
end
end
a = [1,3,5,7,9]
a.map(&:+.(2))
# => [3, 5, 7, 9, 11]
[(1..5), (6..10)].map(&:map.(&:*.(2)))
# => [[2, 4, 6, 8, 10], [12, 14, 16, 18, 20]]
回答by Arup Rakshit
For your example can be done a.map(&2.method(:+)).
对于你的例子可以做到a.map(&2.method(:+))。
Arup-iMac:$ pry
[1] pry(main)> a = [1,3,5,7,9]
=> [1, 3, 5, 7, 9]
[2] pry(main)> a.map(&2.method(:+))
=> [3, 5, 7, 9, 11]
[3] pry(main)>
Here is how it works :-
下面是它的工作原理 :-
[3] pry(main)> 2.method(:+)
=> #<Method: Fixnum#+>
[4] pry(main)> 2.method(:+).to_proc
=> #<Proc:0x000001030cb990 (lambda)>
[5] pry(main)> 2.method(:+).to_proc.call(1)
=> 3
2.method(:+)gives a Methodobject. Then &, on 2.method(:+), actually a call #to_procmethod, which is making it a Procobject. Then follow What do you call the &: operator in Ruby?.
2.method(:+)给出一个Method对象。然后 &, on 2.method(:+),实际上是一个调用#to_proc方法,这使它成为一个Proc对象。然后按照Ruby 中的 &: 运算符是什么?.
回答by Kostas Rousis
As the post you linked to confirms, a.map(&:class)is not a shorthand for a.map {|x| x.class}but for a.map(&:class.to_proc).
当你链接到确认后,a.map(&:class)是不是一个速记a.map {|x| x.class}但a.map(&:class.to_proc)。
This means that to_procis called on whatever follows the &operator.
这意味着to_proc在&运算符后面的任何内容上都会调用它。
So you could give it directly a Procinstead:
所以你可以直接给它一个Proc:
a.map(&(Proc.new {|x| x+2}))
I know that most probably this defeats the purpose of your question but I can't see any other way around it - it's not that you specify which method to be called, you just pass it something that responds to to_proc.
我知道这很可能违背了您的问题的目的,但我看不到任何其他方法 - 不是您指定要调用的方法,而是将响应to_proc.
回答by Agis
Short answer: No.
简短的回答:没有。
Following @rkon's answer, you could also do this:
按照@rkon 的回答,您也可以这样做:
a = [1,3,5,7,9]
a.map &->(_) { _ + 2 } # => [3, 5, 7, 9, 11]
回答by michau
Instead of patching core classes yourself, as in the accepted answer, it's shorter and cleaner to use the functionality of the Facets gem:
不像在接受的答案中那样自己修补核心类,使用Facets gem的功能更短更干净:
require 'facets'
a = [1,3,5,7,9]
a.map &:+.(2)
回答by Pedro Augusto
There is another native option for enumerables which is pretty only for two arguments in my opinion. the class Enumerablehas the method with_objectwhich then returns another Enumerable. So you can call & operator for a method with each item and the object as arguments.
可枚举还有另一个本机选项,在我看来,它仅适用于两个参数。类Enumerable具有with_object方法,然后返回另一个Enumerable。因此,您可以使用每个项目和对象作为参数为方法调用 & 运算符。
Example:
例子:
a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+) # => [3, 5, 7, 9, 11]
a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+) # => [3, 5, 7, 9, 11]
In the case you want more arguments you should repeat the proccess but it's ugly in my opinion:
如果你想要更多的论点,你应该重复这个过程,但我认为这很丑陋:
a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+).to_enum.with_object(5).map(&:+) # => [8, 10, 12, 14, 16]
a = [1,3,5,7,9]
a.to_enum.with_object(2).map(&:+).to_enum.with_object(5).map(&:+) # => [8, 10, 12, 14, 16]
回答by localhostdotdev
I'm not sure about the Symbol#withalready posted, I simplified it quite a bit and it works well:
我不确定Symbol#with已经发布的内容,我对其进行了相当多的简化,并且效果很好:
class Symbol
def with(*args, &block)
lambda { |object| object.public_send(self, *args, &block) }
end
end
(also uses public_sendinstead of sendto prevent calling private methods, also calleris already used by ruby so this was confusing)
(也使用public_send代替send来防止调用私有方法,也caller已经被 ruby 使用,所以这很混乱)

![Ruby 未定义方法“[]”为 nil:NilClass (NoMethodError)](/res/img/loading.gif)