为什么我不能将此类型转换为通用类型?

时间:2018-05-25 12:10:14

标签: scala generics type-conversion generic-programming generic-collections

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

}

在此代码中,我尝试将返回的类型Seq[Double]转换为Seq[T]。在执行呼叫时,T可以是例如DoubleInt

归功于.asInstanceOf[T]

,应实现此转换

错误

代码编译。

但如果我执行它,我会收到以下错误:

  

错误:(25,61)类型不匹配;    发现:( Seq [Double],Seq [Double])=> SEQ [T]    要求:( Seq [Any],Seq [Any])=> SEQ [任意]       ).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]) )

     

错误:(25,13)类型不匹配;    发现:Seq [Any]    要求: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]的转换?

3 个答案:

答案 0 :(得分:3)

首先,不,这段代码没有编译:那些是编译错误,而不是运行时异常。您可以看到,因为它以Error:开头,指向源代码中的确切位置(例外只有行号),并且没有堆栈跟踪。

现在,如果它确实编译了,它就不会起作用,但这是一个单独的问题。

那为什么不编译呢? weights.zip(points).map(...)的类型为Seq[Seq[Double]],因此reduce的签名变为reduce[A1 >: Seq[Double]](op: (A1, A1) => A1): A1。请注意,reduce的参数的返回和参数类型必须匹配,在您的情况下,它们不会(您有(Seq[Double], Seq[Double]) => Seq[T])。本身就足够了,不能编译。

整个weights.zip(points).map(...).reduce(...)的预期类型是Seq[T],因此编译器需要选择A1

  1. 超出Seq[Double]的超类型以满足约束

  2. Seq[T]的子类型,使返回类型匹配

  3. 这样的类型不存在(没有T的附加约束),但是如果它确实存在Seq[SomeType],那么就编译器应该得到的那样。为什么它最终显示Any,我真的不明白。

      

    如何实现从Seq [Double]到Seq [T]的转换?

    如果你有weights: Seq[T], points: Seq[Seq[T]],那就更有意义了。在这种情况下,请使用Numeric。 Stack Overflow上有很多答案,外面解释如何,例如, enter image description here

    对于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)
    
    }
    

答案 1 :(得分:2)

我从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](权重= Seq(1.1,1.3),Seq(Seq(1.1,1.2),Seq(1.3,1.4)))

答案 2 :(得分:2)

因此类型类的效果相同:

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 =>使用情况。