foldLeft 上的 scala 参数化类型
scala parameterized type on foldLeft
给定参数化方法的以下签名
def double[A <: Byte](in:List[A]): List[A] = {
//double the values of the list using foldLeft
//for ex. something like:
in.foldLeft(List[A]())((r,c) => (2*c) :: r).reverse
//but it doesn't work! so..
}
在处理参数化类型化 foldLeft
之前,我试图获得以下内容
def plainDouble[Int](in:List[Int]): List[Int] = {
in.foldLeft(List[Int]())((r:List[Int], c:Int) => {
var k = 2*c
println("r is ["+r+"], c is ["+c+"]")
//want to prepend to list r
// k :: r
r
})
}
但是,这会导致以下错误:
$scala fold_ex.scala
error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: scala.Int)scala.Int <and>
(x: Char)scala.Int <and>
(x: Short)scala.Int <and>
(x: Byte)scala.Int
cannot be applied to (Int(in method plainDouble))
val k = 2*c
^
one error found
如果我将 def 的签名更改为以下内容:
def plainDouble(in:List[Int]): List[Int] = { ...}
有效,输出为:
val in = List(1,2,3,4,5)
println("in "+ in + " plainDouble ["+plainDouble(in)+"]")
是
in List(1, 2, 3, 4, 5) plainDouble [List(2, 4, 6, 8, 10)]
如果我遗漏了一些非常明显的东西,我深表歉意。
问题是一种名称阴影:
def plainDouble[Int](in:List[Int]): List[Int] = {
^^^
// this is a type parameter called "Int"
您正在声明一个名为 Int
的类型变量,同时还尝试使用具体类型 Int
,这会导致混淆。例如,如果您删除类型变量(因为实际上并未使用它)或将其重命名为 I
,则代码会编译。
@DNA 是正确的,因为 plainDouble[Int]
声明了一个名为 Int
的类型参数,它与实际类型无关。因此,您尝试使其成为非泛型实际上仍然是泛型,但以一种不会很快显现的方式。
但是原来的问题呢?
scala> def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r)
<console>:15: error: type mismatch;
found : x.type (with underlying type Int)
required: A
def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r).reverse
^
这里的问题是 2 * c
是 Int
,而不是 A
。 Int
return 上的 *(byte: Byte)
方法是另一个 Int
。因此消息 (with underlying type Int)
。请注意,如果您转换为 A
,它会编译:
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => (2*c).toByte.asInstanceOf[A] :: r).reverse
请注意,在投射到 A
之前,我还必须调用 toByte
。这不完全是泛型工作的一个光辉例子,但关键是不兼容的 return 类型导致了错误。
另请注意,如果您删除 2 *
:
,它不会发生
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => c :: r).reverse
编辑:
您可能会考虑对这样的泛型使用 Numeric
特性。
import scala.math.Numeric.Implicits._
def double[A: Numeric](in: List[A])(implicit i2a: Int => A): List[A] =
in.map(_ * 2)
这依赖于隐含的 Numeric[A]
可用于您的数字类型(在 scala.math.Numeric
对象中,几乎任何您想要的数字类型)。它还依赖于从 Int
到 A
的隐式转换,因此我们可以编写 a * 2
。我们可以使用 +
代替此约束:
def double[A: Numeric](in: List[A]): List[A] = in.map(a => a + a)
给定参数化方法的以下签名
def double[A <: Byte](in:List[A]): List[A] = {
//double the values of the list using foldLeft
//for ex. something like:
in.foldLeft(List[A]())((r,c) => (2*c) :: r).reverse
//but it doesn't work! so..
}
在处理参数化类型化 foldLeft
之前,我试图获得以下内容def plainDouble[Int](in:List[Int]): List[Int] = {
in.foldLeft(List[Int]())((r:List[Int], c:Int) => {
var k = 2*c
println("r is ["+r+"], c is ["+c+"]")
//want to prepend to list r
// k :: r
r
})
}
但是,这会导致以下错误:
$scala fold_ex.scala
error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: scala.Int)scala.Int <and>
(x: Char)scala.Int <and>
(x: Short)scala.Int <and>
(x: Byte)scala.Int
cannot be applied to (Int(in method plainDouble))
val k = 2*c
^
one error found
如果我将 def 的签名更改为以下内容:
def plainDouble(in:List[Int]): List[Int] = { ...}
有效,输出为:
val in = List(1,2,3,4,5)
println("in "+ in + " plainDouble ["+plainDouble(in)+"]")
是
in List(1, 2, 3, 4, 5) plainDouble [List(2, 4, 6, 8, 10)]
如果我遗漏了一些非常明显的东西,我深表歉意。
问题是一种名称阴影:
def plainDouble[Int](in:List[Int]): List[Int] = {
^^^
// this is a type parameter called "Int"
您正在声明一个名为 Int
的类型变量,同时还尝试使用具体类型 Int
,这会导致混淆。例如,如果您删除类型变量(因为实际上并未使用它)或将其重命名为 I
,则代码会编译。
@DNA 是正确的,因为 plainDouble[Int]
声明了一个名为 Int
的类型参数,它与实际类型无关。因此,您尝试使其成为非泛型实际上仍然是泛型,但以一种不会很快显现的方式。
但是原来的问题呢?
scala> def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r)
<console>:15: error: type mismatch;
found : x.type (with underlying type Int)
required: A
def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r).reverse
^
这里的问题是 2 * c
是 Int
,而不是 A
。 Int
return 上的 *(byte: Byte)
方法是另一个 Int
。因此消息 (with underlying type Int)
。请注意,如果您转换为 A
,它会编译:
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => (2*c).toByte.asInstanceOf[A] :: r).reverse
请注意,在投射到 A
之前,我还必须调用 toByte
。这不完全是泛型工作的一个光辉例子,但关键是不兼容的 return 类型导致了错误。
另请注意,如果您删除 2 *
:
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => c :: r).reverse
编辑:
您可能会考虑对这样的泛型使用 Numeric
特性。
import scala.math.Numeric.Implicits._
def double[A: Numeric](in: List[A])(implicit i2a: Int => A): List[A] =
in.map(_ * 2)
这依赖于隐含的 Numeric[A]
可用于您的数字类型(在 scala.math.Numeric
对象中,几乎任何您想要的数字类型)。它还依赖于从 Int
到 A
的隐式转换,因此我们可以编写 a * 2
。我们可以使用 +
代替此约束:
def double[A: Numeric](in: List[A]): List[A] = in.map(a => a + a)