Scala方法和更高类型的参数

vic*_*aba 4 generics scala type-parameter

我正在尝试在scala中定义一个方法,该方法采用的泛型类型S[_] <: Seq[Double]并返回S [FixedLoad](FixedLoad是具体类型)。但是我的实现给我错误,我不知道为什么。尽管我已经尝试了很多次以了解参数类型和种类繁多的类型,但是我的知识却增长得很慢。

我要实现的目标是不丢失S的具体类型(序列子类型)。

这是代码:

import scala.collection.generic.CanBuildFrom

class FixedLoad(val id: Int, val positionInT: Int, val amplitude: Double) {
  override def toString: String = s"FixedLoad($id, $positionInT, $amplitude)"
}

object Load {

  implicit def toFixedLoads[S[_] <: Seq[Double]](l: S[Double])(implicit cbf: CanBuildFrom[Nothing, FixedLoad, S[FixedLoad]]): S[FixedLoad] = {
    l.map(_ => new FixedLoad(1, 1, 1)).to[S]
  }

  def main(args: Array[String]): Unit = {
    println(toFixedLoads(List(1.0, 2.0, 3.0)))
  }

}
Run Code Online (Sandbox Code Playgroud)

和错误:

Error:(16, 13) inferred type arguments [List] do not conform to method toFixedLoads's type parameter bounds [S[_] <: Seq[Double]]
    println(toFixedLoads(List(1.0, 2.0, 3.0)))

Error:(16, 30) type mismatch;
 found   : List[Double]
 required: S[Double]
    println(toFixedLoads(List(1.0, 2.0, 3.0)))
Run Code Online (Sandbox Code Playgroud)

slo*_*ouc 5

简短答案:

更改toFixedLoads[S[_] <: Seq[Double]]toFixedLoads[S[A] <: Seq[A]]

长答案:

当您说时S[_],这是一种较高的类型。换句话说,它是一个类型构造函数。这意味着需要一个类型来产生最终的正确类型。这里有些例子:

  • List-采用一种类型,例如Int,以产生适当的类型List[Int]
  • Option-采用一种类型,例如Int,以产生适当的类型Option[Int]

等等

这种类型的构造函数通常表示为* -> *。您提供一种类型,然后又得到一种类型。也有其他种类。例如,Map并且Either需要两种类型来产生适当的类型(例如Map[Int, String]Either[Error, Foo]),因此它们的类型是* -> * -> *。将其视为咖喱类型构造函数;接受一个类型并返回一个接受该类型的函数,然后得到最终的正确类型。换句话说,需要两种类型来产生最终的正确类型。您可能还需要一个类型构造函数,该类型构造函数需要一个类型构造函数来构建适当的类型(例如Monad[F[_]]),在这种情况下,该类型是(* -> *) -> *(例如List -> Monad[List])。

因此,当您说您的方法期望一个类型为参数的参数S[Double]并传递时List(1.0, 2.0, 3.0),编译器会推断SList,并且它抱怨List[A]不是Seq[Double]any 的子类型A。解决此问题的第一个尝试可能是F[_] <: Seq[_],但由于内部类型仍然无法对齐,因此无法编译。我们需要用类似的“连接”它们F[A] <: Seq[A] for some A,可以将其写为F[A] <: Seq[A]

一个好问题可能是“我可以说S <: Seq[Double]吗?” 当然,S代表正确的类型,所以您完全可以!这样的事情就可以了:

def foo[S <: Seq[Double]](s: S) = println(s)
foo(List(1.0, 2.0)) // prints List(1.0, 2.0)
Run Code Online (Sandbox Code Playgroud)

但是,当然,其中S有一个“洞”,因为您的方法参数的类型是S[Double],所以不适用于您的情况。