为什么我不能将这种类型转换为通用类型?
Why can't I convert this type into a generic one?
def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]]) : Seq[T] = {
weights.zip(points).map(
weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
}
在此代码中,我尝试将 return 的类型 Seq[Double]
转换为 Seq[T]
。在执行调用时,T
可能是例如Double
或 Int
.
这个转换应该感谢.asInstanceOf[T]
。
错误
代码编译。
但是如果我执行它,我会得到以下错误:
Error:(25, 61) type mismatch;
found : (Seq[Double], Seq[Double]) => Seq[T]
required: (Seq[Any], Seq[Any]) => Seq[Any]
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
Error:(25, 13) type mismatch;
found : Seq[Any]
required: Seq[T]
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
问题
为什么会执行失败?如何实现从 Seq[Double]
到 Seq[T]
的转换?
首先,不,这段代码无法编译:那些是编译错误,不是运行时异常。你可以看到,因为它以 Error:
开头,指向源代码中的确切位置(异常只有行号),并且没有堆栈跟踪。
现在,如果它确实编译了,它就不会工作,但这是一个单独的问题。
那么为什么它不能编译呢? weights.zip(points).map(...)
的类型是Seq[Seq[Double]]
,所以reduce
的签名变成了reduce[A1 >: Seq[Double]](op: (A1, A1) => A1): A1
。请注意 return 和 reduce
参数的参数类型必须匹配,而在您的情况下它们不匹配(您有 (Seq[Double], Seq[Double]) => Seq[T]
)。这本身就足以不编译。
整个weights.zip(points).map(...).reduce(...)
的预期类型是Seq[T]
,所以编译器需要选择A1
,即:
Seq[Double]
的超类型以满足约束
Seq[T]
的子类型,使 return 类型匹配
这样的类型不存在(对 T
没有额外的限制),但如果存在,它将是 Seq[SomeType]
,这是编译器应该得到的。为什么它最终显示 Any
,我真的不明白。
How to achieve this conversion from a Seq[Double] to a Seq[T] ?
如果你有 weights: Seq[T], points: Seq[Seq[T]]
就更有意义了。在这种情况下,使用 Numeric
。 Stack Overflow 和外部有很多答案解释如何,例如Scala equivalent of Java's Number.
对于weights: Seq[Double], points: Seq[Seq[Double]]
,我会添加一个函数Double => T
作为额外的参数:
def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]])(fromDouble: Double => T) : Seq[T] = {
weights.zip(points).map(
weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => coordinate_points._1 + coordinate_points._2)).map(fromDouble)
}
我补充了 Alexey 的回答。
我会将 fromDouble 声明为隐式并将转换器函数创建为隐式值,您可以按设计使用函数。
例如:
object DoubleConverters {
implicit val doubleToDouble: Double => Double = identity
implicit val doubleToInt: Double => Int = _.round.toInt
}
def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: Double => T) : Seq[T] =
weights.zip(points)
.map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
.reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
.map(converter)
// sample call
val result = linearInterpolation[Double]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
//示例调用
val result = linearInterpolation[Double]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
因此与类型 class 具有相同的效果:
trait DoubleConverter[T] {
def convert(d: Double): T
}
object DoubleConverter {
implicit val doubleToInt: DoubleConverter[Int] = new DoubleConverter[Int] {
override def convert(d: Double): Int = d.round.toInt
}
implicit val doubleToDouble: DoubleConverter[Double] = new DoubleConverter[Double] {
override def convert(d: Double): Double = d
}
}
def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: DoubleConverter[T]) : Seq[T] =
weights.zip(points)
.map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
.reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
.map(converter.convert)
// sample call
val result = linearInterpolation[Int]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
看到用法保持不变。我们避免意外使用 Double => Int。
def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]]) : Seq[T] = {
weights.zip(points).map(
weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
}
在此代码中,我尝试将 return 的类型 Seq[Double]
转换为 Seq[T]
。在执行调用时,T
可能是例如Double
或 Int
.
这个转换应该感谢.asInstanceOf[T]
。
错误
代码编译。
但是如果我执行它,我会得到以下错误:
Error:(25, 61) type mismatch; found : (Seq[Double], Seq[Double]) => Seq[T] required: (Seq[Any], Seq[Any]) => Seq[Any] ).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
Error:(25, 13) type mismatch; found : Seq[Any] required: Seq[T] ).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))
问题
为什么会执行失败?如何实现从 Seq[Double]
到 Seq[T]
的转换?
首先,不,这段代码无法编译:那些是编译错误,不是运行时异常。你可以看到,因为它以 Error:
开头,指向源代码中的确切位置(异常只有行号),并且没有堆栈跟踪。
现在,如果它确实编译了,它就不会工作,但这是一个单独的问题。
那么为什么它不能编译呢? weights.zip(points).map(...)
的类型是Seq[Seq[Double]]
,所以reduce
的签名变成了reduce[A1 >: Seq[Double]](op: (A1, A1) => A1): A1
。请注意 return 和 reduce
参数的参数类型必须匹配,而在您的情况下它们不匹配(您有 (Seq[Double], Seq[Double]) => Seq[T]
)。这本身就足以不编译。
整个weights.zip(points).map(...).reduce(...)
的预期类型是Seq[T]
,所以编译器需要选择A1
,即:
Seq[Double]
的超类型以满足约束Seq[T]
的子类型,使 return 类型匹配
这样的类型不存在(对 T
没有额外的限制),但如果存在,它将是 Seq[SomeType]
,这是编译器应该得到的。为什么它最终显示 Any
,我真的不明白。
How to achieve this conversion from a Seq[Double] to a Seq[T] ?
如果你有 weights: Seq[T], points: Seq[Seq[T]]
就更有意义了。在这种情况下,使用 Numeric
。 Stack Overflow 和外部有很多答案解释如何,例如Scala equivalent of Java's Number.
对于weights: Seq[Double], points: Seq[Seq[Double]]
,我会添加一个函数Double => T
作为额外的参数:
def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]])(fromDouble: Double => T) : Seq[T] = {
weights.zip(points).map(
weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => coordinate_points._1 + coordinate_points._2)).map(fromDouble)
}
我补充了 Alexey 的回答。 我会将 fromDouble 声明为隐式并将转换器函数创建为隐式值,您可以按设计使用函数。 例如:
object DoubleConverters {
implicit val doubleToDouble: Double => Double = identity
implicit val doubleToInt: Double => Int = _.round.toInt
}
def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: Double => T) : Seq[T] =
weights.zip(points)
.map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
.reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
.map(converter)
// sample call
val result = linearInterpolation[Double]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
//示例调用 val result = linearInterpolation[Double]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
因此与类型 class 具有相同的效果:
trait DoubleConverter[T] {
def convert(d: Double): T
}
object DoubleConverter {
implicit val doubleToInt: DoubleConverter[Int] = new DoubleConverter[Int] {
override def convert(d: Double): Int = d.round.toInt
}
implicit val doubleToDouble: DoubleConverter[Double] = new DoubleConverter[Double] {
override def convert(d: Double): Double = d
}
}
def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: DoubleConverter[T]) : Seq[T] =
weights.zip(points)
.map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
.reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
.map(converter.convert)
// sample call
val result = linearInterpolation[Int]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))
看到用法保持不变。我们避免意外使用 Double => Int。