Ruby:为什么这种使用map的方式会产生错误?

时间:2023-01-16 16:39:17

I tried to shorten

我试图缩短

values.map { |value| value.gsub!("\n", ' ') }

值。地图{ | |价值value.gsub !(“\ n”、“)}

with

values.map(&:gsub!("\n", ' '))

values.map(&:gsub !(“\ n”,' '))

but it gives me an:

但它给了我一个:

SyntaxError:
...csv_creator.rb:40: syntax error, unexpected '(', expecting ')'
     values.map(&:gsub!("\n", ' '))

Anyone know what's going on?

有人知道发生了什么吗?

3 个解决方案

#1


3  

&:foo may erroneously be seen as &: plus foo (terms like "pretzel colon" reinforce this mistaken view). But no method foo is being called here. &:foo is actually & plus :foo, the latter being a plain symbol.

&:foo可能被错误地认为是&:+ foo(像“pretzel冒号”这样的术语强化了这个错误的观点)。但是这里没有调用foo方法。&:foo实际上是& +:foo,后者是一个普通的符号。

When calling a method, &object (without :) invokes object.to_proc (which is supposed to return a Proc) and passes the returned proc as a block argument to the method.

调用方法时,&object(没有:)调用对象。to_proc(应该返回一个Proc)并将返回的Proc作为块参数传递给方法。

object often happens to be a symbol and Symbol#to_proc's implementation would look somehow like this in Ruby: (it's actually written in C)

对象通常是一个符号和符号#to_proc的实现在Ruby:(它实际上是用C编写的)中看起来像这样

class Symbol
  def to_proc
    proc { |object, *args| object.public_send(self, *args) }
  end
end

So this:

所以这个:

method(&:symbol)

effectively becomes this:

有效地成为这个:

method { |object, *args| object.public_send(:symbol, *args) }

or, if method doesn't yield multiple values (like map), it's simply:

或者,如果方法不产生多个值(如map),它只是:

method { |object| object.public_send(:symbol) }

Obviously, you can't pass additional arguments via a symbol.

显然,不能通过符号传递附加参数。

But ... object doesn't have to be a symbol. You could use another class with a custom to_proc implementation. Let's abuse Array for demonstration purposes:

但是…对象不一定是符号。您可以使用另一个具有自定义to_proc实现的类。让我们滥用数组进行演示:

class Array
  def to_proc
    method, *args = self
    proc { |obj| obj.public_send(method, *args) }
  end
end

This hack would allow you to write:

你可以这样写:

["foo\nbar", "baz\nqux"].map(&[:gsub, "\n", '-'])
#=> ["foo-bar", "baz-qux"]

#2


3  

&:method notation is using #to_proc method, which is capable of converting symbol to Proc object. It can't be used as a shortcut if you need to provide additional arguments to called method.

方法符号使用#to_proc方法,它可以将符号转换为Proc对象。如果需要为所调用方法提供附加参数,则不能将其用作快捷方式。

Longer explanation about #to_proc can be found in separate answer: What does to_proc method mean?

关于#to_proc的更详细的解释可以在单独的答案中找到:to_proc方法是什么意思?

#3


1  

Alternatives

String#methods

Just to show what could be done : you could define String methods without arguments.

只是为了说明可以做什么:您可以定义没有参数的字符串方法。

class String
  def replace_newlines!(replace = ' ')
    gsub!("\n", replace)
  end

  def replace_newlines(replace = ' ')
    gsub("\n", replace)
  end
end

p new_values = values.map(&:replace_newlines)
#=> ["1 2", "a b"]

p values.each(&:replace_newlines!)
#=> ["1 2", "a b"]

Sadly, refinements wouldn't work with to_proc.

遗憾的是,改进不适用于to_proc。

Proc

Another possibility would be to define a new Proc, without monkey-patching String :

另一种可能是定义一个新的Proc,而不是monkey-patching字符串:

my_gsub = proc { |string| string.gsub("\n", ' ') }
p new_values = values.map(&my_gsub)
#=> ["1 2", "a b"]

each/map/gsub/gsub!

Note that map doesn't make much sense when used with ! methods. You should either :

注意,map在使用时没有多大意义!方法。你应该:

  • use map with gsub
  • 使用地图gsub
  • or use each with gsub!
  • 或使用每一个与gsub!

#1


3  

&:foo may erroneously be seen as &: plus foo (terms like "pretzel colon" reinforce this mistaken view). But no method foo is being called here. &:foo is actually & plus :foo, the latter being a plain symbol.

&:foo可能被错误地认为是&:+ foo(像“pretzel冒号”这样的术语强化了这个错误的观点)。但是这里没有调用foo方法。&:foo实际上是& +:foo,后者是一个普通的符号。

When calling a method, &object (without :) invokes object.to_proc (which is supposed to return a Proc) and passes the returned proc as a block argument to the method.

调用方法时,&object(没有:)调用对象。to_proc(应该返回一个Proc)并将返回的Proc作为块参数传递给方法。

object often happens to be a symbol and Symbol#to_proc's implementation would look somehow like this in Ruby: (it's actually written in C)

对象通常是一个符号和符号#to_proc的实现在Ruby:(它实际上是用C编写的)中看起来像这样

class Symbol
  def to_proc
    proc { |object, *args| object.public_send(self, *args) }
  end
end

So this:

所以这个:

method(&:symbol)

effectively becomes this:

有效地成为这个:

method { |object, *args| object.public_send(:symbol, *args) }

or, if method doesn't yield multiple values (like map), it's simply:

或者,如果方法不产生多个值(如map),它只是:

method { |object| object.public_send(:symbol) }

Obviously, you can't pass additional arguments via a symbol.

显然,不能通过符号传递附加参数。

But ... object doesn't have to be a symbol. You could use another class with a custom to_proc implementation. Let's abuse Array for demonstration purposes:

但是…对象不一定是符号。您可以使用另一个具有自定义to_proc实现的类。让我们滥用数组进行演示:

class Array
  def to_proc
    method, *args = self
    proc { |obj| obj.public_send(method, *args) }
  end
end

This hack would allow you to write:

你可以这样写:

["foo\nbar", "baz\nqux"].map(&[:gsub, "\n", '-'])
#=> ["foo-bar", "baz-qux"]

#2


3  

&:method notation is using #to_proc method, which is capable of converting symbol to Proc object. It can't be used as a shortcut if you need to provide additional arguments to called method.

方法符号使用#to_proc方法,它可以将符号转换为Proc对象。如果需要为所调用方法提供附加参数,则不能将其用作快捷方式。

Longer explanation about #to_proc can be found in separate answer: What does to_proc method mean?

关于#to_proc的更详细的解释可以在单独的答案中找到:to_proc方法是什么意思?

#3


1  

Alternatives

String#methods

Just to show what could be done : you could define String methods without arguments.

只是为了说明可以做什么:您可以定义没有参数的字符串方法。

class String
  def replace_newlines!(replace = ' ')
    gsub!("\n", replace)
  end

  def replace_newlines(replace = ' ')
    gsub("\n", replace)
  end
end

p new_values = values.map(&:replace_newlines)
#=> ["1 2", "a b"]

p values.each(&:replace_newlines!)
#=> ["1 2", "a b"]

Sadly, refinements wouldn't work with to_proc.

遗憾的是,改进不适用于to_proc。

Proc

Another possibility would be to define a new Proc, without monkey-patching String :

另一种可能是定义一个新的Proc,而不是monkey-patching字符串:

my_gsub = proc { |string| string.gsub("\n", ' ') }
p new_values = values.map(&my_gsub)
#=> ["1 2", "a b"]

each/map/gsub/gsub!

Note that map doesn't make much sense when used with ! methods. You should either :

注意,map在使用时没有多大意义!方法。你应该:

  • use map with gsub
  • 使用地图gsub
  • or use each with gsub!
  • 或使用每一个与gsub!