为什么scala无法从2个函数推断出通配符类型?

时间:2016-06-26 20:44:24

标签: scala generics type-inference unbounded-wildcard

我定义了以下功能:

import org.apache.spark.sql.catalyst.{ScalaReflection}

import ScalaReflection.universe
import universe.TypeTag

def scalaTypesFor(dataType: DataType): Set[TypeTag[_]] = ...

def scalaTypeOpt: Option[TypeTag[_]] = ...

val catalystType = ...
scalaTypeOpt.map(v => Set(v))
      .getOrElse{
        val default = scalaTypesFor(catalystType)
        default
      }

在这种情况下,scalaTypesFor和scalaTypeOpt都应该生成带有通配符参数的TypeTag,它们应该是相同的类型。但是,编译器给了我以下错误:

Error:(29, 51) inferred type arguments [scala.collection.immutable.Set[_117] forSome { type _$2; type _117 >: org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_$2] <: org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_] }] do not conform to method getOrElse's type parameter bounds [B >: scala.collection.immutable.Set[org.apache.spark.sql.catalyst.ScalaReflection.universe.TypeTag[_$2]] forSome { type _$2 }]
    val effective = scalaTypeOpt.map(v => Set(v)).getOrElse{
                                                  ^

类型推断有什么问题以及如何解决?

1 个答案:

答案 0 :(得分:1)

我认为问题在于你有两种未知的类型_并且不能保证它们是兼容的。 scala中的不可变集合也是不正确的(在人们开始评论之前,已经有很多讨论,最后的话就是这样,确实没有真正的根本原因使它们不能协变)所以这往往会产生讨厌打字问题。

没有编译器可以测试,但你可以尝试一些事情

  1. (不太可行)将Set的类型归为Set[TypeTag[_]](v)
  2. 更改您的代码,以便您允许编译器捕获未知类型并向自己证明它与此类型相同:

    def scalaTypesFor[T](dataType: DataType): Set[TypeTag[T]] = ???
    
    def scalaTypeOpt[T]: Option[TypeTag[T]] = ???
    
    def xform[T] = {
       val catalystType = ???
       scalaTypeOpt[T].map(v => Set(v))
          .getOrElse{
           val default = scalaTypesFor[T](catalystType)
           default
         }
     }
    
  3. 或者如果你可以将它们作为本地defs

        def xform[T] = {
           def scalaTypesFor(dataType: DataType): Set[TypeTag[T]] = ???
           def scalaTypeOpt: Option[TypeTag[T]] = ???
    
           val catalystType = ???
           scalaTypeOpt.map(v => Set(v))
              .getOrElse{
               val default = scalaTypesFor(catalystType)
               default
             }
         }