Scala 类型检查

Scala type check

如何进行此类型检查?

trait Test[A] {
  type Output = A
  def get: Iterable[A]
  def check(a: A): Boolean
}

object A {
  def fs: List[Test[_]] = ???
  def test = for{f <- fs
    a <- f.get
    if f.check(a)} println(a)
}

它抱怨

<console>:12: error: type mismatch;
 found   : a.type (with underlying type _)
 required: _
           if f.check(a)} println(a)

尝试 #1(失败)

object A {
  def fs: List[Test[_]] = ???
  def test = for{f <- fs
    a <- f.get
    if f.check(a.asInstanceOf[f.Output])} println(a)
}

但后来我遇到了同样的问题:

<console>:12: error: type mismatch;
 found   : f.Output
    (which expands to)  _
 required: _
               if f.check(a.asInstanceOf[f.Output])} println(a)

尝试 #2(失败)

了解了一些存在类型后,我正在尝试替换下划线 -- 在测试级别,因为并非所有 A 都相同

object A {
  def fs: List[Test[A] forSome { type A }] = ???
  def test = for{f <- fs
    a <- f.get
    if f.check(a)} println(a)
}

它抱怨:

<console>:12: error: type mismatch;
 found   : a.type (with underlying type A)
 required: A
           if f.check(a)} println(a)

如何摆脱这种噩梦?

解决方案是将存在类型推入

object A {
  def fs: List[Test[A forSome { type A }]] = ???
  def test = for{f <- fs
    a <- f.get
    if f.check(a)} println(a)
}

结果成功了。

基本问题是 Scala 编译器没有注意到存在性隐藏的类型必须相同。

有两种解决方案:

  1. 创建一个同时调用 getcheck 的方法:

    object A {
      private def getChecked[A](f: Test[A]) = f.get.withFilter(f.check)
    
      def fs: List[Test[_]] = ???
      def test = for { f <- fs; a <- getChecked(f) } println(a)
    
  2. 使用类型变量模式为存在命名。不幸的是,这在 for 中似乎不起作用,因此您需要先将其脱糖:

    // equivalent to your initial code
    def test = fs.flatMap { f => f.get.withFilter { a => f.check(a) } }.
                  foreach { a => println(a) }
    
    // with a type variable
    def test = fs.flatMap { case f: Test[x] => f.get.withFilter { a => f.check(a) } }.
                  foreach { a => println(a) }