2

给定参数化方法的以下签名

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)]

如果我遗漏了一些非常明显的东西,我深表歉意。

4

2 回答 2

3

问题是一种名称阴影:

def plainDouble[Int](in:List[Int]): List[Int] = {
                ^^^
      // this is a type parameter called "Int"

您正在声明一个名为 的类型变量Int,同时还尝试使用具体类型Int,这会导致混淆。例如,如果您删除类型变量(因为它实际上并未使用)或将其重命名I为 ,则代码将编译。

于 2015-04-01T16:11:11.637 回答
1

@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$1.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。on*(byte: Byte)方法Int返回另一个. 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

请注意,toByte在转换为A. 这并不是泛型工作的一个光辉例子,但关键是不兼容的返回类型导致了错误。

另请注意,如果您删除它不会发生2 *

def double[A <: Byte](in: List[A]): List[A] =
    in.foldLeft(List.empty[A])((r,c) => c :: r).reverse

编辑:

您可能会考虑将Numerictrait 用于这样的泛型。

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对象中,对于您想要的几乎任何数字类型)。它还依赖于从Intto可用的隐式转换A,因此我们可以编写a * 2. 我们可以通过使用+来删除这个约束:

def double[A: Numeric](in: List[A]): List[A] = in.map(a => a + a)
于 2015-04-01T16:57:50.647 回答