为什么以下代码发出错误?
['hello','stack','overflow'].inject{|memo,s|memo+s.length}
TypeError: can't convert Fixnum into String
from (irb):2:in `+'
from (irb):2:in `block in irb_binding'
from (irb):2:in `each'
from (irb):2:in `inject'
from (irb):2
Run Code Online (Sandbox Code Playgroud)
如果传递初始值,则可以正常工作:
['hello','stack','overflow'].inject(0){|memo,s|memo+s.length}
=> 18
Run Code Online (Sandbox Code Playgroud)
正如错误消息已经告诉你的那样,问题是你有一个 TypeError.仅仅因为Ruby是动态和隐式类型的,并不意味着你不必考虑类型.
Enumerable#inject没有显式累加器的类型(通常称为reduce)类似于
reduce :: [a] ? (a ? a ? a) ? a
Run Code Online (Sandbox Code Playgroud)
或者用一种更简洁的符号来构建
Enumerable[A]#inject {|A, A| A } ? A
Run Code Online (Sandbox Code Playgroud)
您会注意到所有类型都是相同的.元素的类型Enumerable块的两个参数类型,块的返回类型以及整个方法的返回类型.
在您的情况下,块的类型不会加起来.该块传递两次String,它应该返回一个String.但是你+在第一个参数(也就是a String)上调用方法,其参数是一个Integer.但是String#+并不需要Integer它只需要一个String或多个可以转换为a的String东西,即响应的东西#to_str.这就是为什么你得到TypeError了String#+.
Enumerable#inject 带有显式累加器的类型(通常称为fold)类似于
fold :: [b] ? a ? (a ? b ? a) ? a
Run Code Online (Sandbox Code Playgroud)
要么
Enumerable[B]#inject(A) {|A, B| A } ? A
Run Code Online (Sandbox Code Playgroud)
在这里,您可以看到累加器可以具有与集合的元素类型不同的类型.这正是您所需要的.
这两条规则通常可以Enumerable#inject解决所有相关问题:
当你做某事时,规则#1通常会咬你
acc[key] = value
Run Code Online (Sandbox Code Playgroud)
在您的块中,因为赋值评估为指定的值,而不是赋值的接收者.你必须用它替换它
acc.tap { acc[key] = value }
Run Code Online (Sandbox Code Playgroud)
在您的特定情况下,已经提到了两种解决方案.要么使用显式累加器
ary.reduce(0){|acc, e| acc + e.length }
Run Code Online (Sandbox Code Playgroud)
或首先转换为整数
ary.map(&:length).reduce(:+)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2283 次 |
| 最近记录: |