【问题标题】:Scala: Type mismatch with nested genericsScala:类型与嵌套泛型不匹配
【发布时间】:2016-10-21 21:36:03
【问题描述】:

我创建了下面的人为示例来展示我想要完成的工作。我正在寻找一个工厂,它将吐出一个类,该类使用它将处理的特定类型的请求进行参数化。我以为我了解泛型,但现在我怀疑自己。 :)

object SourceFactory {
  def apply[T <: Source[_ <: RequestContext]](x: String): Source[_ <: RequestContext] = { 
    x match {
      case "a" => new FooSource
    }   
  }
}

object RequestContextFactory {
  def apply[T >: RequestContext](x: String): T = { 
    x match {
      case "a" => FooRequestContext()
    }   
  }
}

abstract class RequestContext
case class FooRequestContext() extends RequestContext

abstract class Source[T <: RequestContext] {
  def get(ctx: T): Unit
}

class FooSource extends Source[FooRequestContext] {
  def get(ctx: FooRequestContext): Unit = {}
}

object Test extends App {
  val source = SourceFactory("a")
  val ctx = RequestContextFactory("a")

  source.get(ctx)
}

结果:

编译器异常错误:第 32 行:类型不匹配; 发现:Evaluator__da15fb805d29b29227bc28ccae6cd07d2c04cb40_1274353927.Test.ctx.type(具有基础类型RequestContext) 需要:_$2 source.get(ctx)

提前感谢您的帮助!

【问题讨论】:

    标签: scala generics types


    【解决方案1】:

    Scala 绝对无法在SourceFactory.applyRequestContextFactory.apply 中推断出T,因为它没有出现在参数中。您正在调用SourceFactory[Nothing]RequestContextFactory[RequestContext](第二个只是因为def apply[T &gt;: RequestContext] 中可能存在拼写错误)。

    你可以明确地给T

    object SourceFactory {
      def apply[T <: RequestContext](x: String): Source[T] = { 
        (x match {
          case "a" => new FooSource
        }).asInstanceOf[Source[T]]
      }
    }
    
    object RequestContextFactory {
      def apply[T <: RequestContext](x: String): T = { 
        (x match {
          case "a" => FooRequestContext()
        }).asInstanceOf[T]   
      }
    }
    
    object Test extends App {
      val source = SourceFactory[FooRequestContext]("a")
      val ctx = RequestContextFactory[FooRequestContext]("a")
    
      source.get(ctx)
    }
    

    注意你最终需要演员表:这应该暗示这是一个糟糕的设计!问题是您的返回 type 取决于参数的 value。 Scala 确实支持这种称为路径依赖类型的形式,但它不适用于这里。您也可以尝试删除类型参数并仅使用存在:

    object SourceFactory {
      def apply(x: String): Source[_ <: RequestContext] = { 
        x match {
          case "a" => new FooSource
        }
      }
    }
    
    object RequestContextFactory {
      def apply(x: String): RequestContext = { // equivalent to _ <: RequestContext
        x match {
          case "a" => FooRequestContext()
        }
      }
    }
    
    object Test extends App {
      val source = SourceFactory("a")
      val ctx = RequestContextFactory("a")
    
      source.get(ctx)
    }
    

    不是SourceFactoryResourceContextFactory 中没有强制转换,但它们的返回类型之间也没有任何关系,所以source.get(ctx) 不会编译!

    根据您的要求,实际可行的方法是将返回值配对为一个类型:

    case class SourceAndRequestContext[T <: RequestContext](src: Source[T], ctx: T) {
      def get() = src.get(ctx)
    }
    
    object SourceAndRequestContextFactory {
      def apply(x: String): SourceAndRequestContext[_ <: RequestContext] = x match {
        case "a" => SourceAndRequestContext(new FooSource, FooRequestContext())
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-21
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      相关资源
      最近更新 更多