【问题标题】:What is the correct way to implement trait with generics in Scala?在 Scala 中使用泛型实现 trait 的正确方法是什么?
【发布时间】:2014-09-03 17:24:13
【问题描述】:

我有一些简单的特征(下例中的实体),这些特征在我的应用程序中由案例类扩展。我想创建一个 EntityMapper 特征,它提供了一个接口来处理扩展实体特征的案例类(下例中的 Foo)。我认为我应该能够使用泛型和边界相当容易地做到这一点,但我已经花了几个小时在它上面,但我还没有让它正常工作。下面的代码是我认为我应该能够做的,但它因编译器错误而失败。错误是

Test.scala:15: error: value id is not a member of type parameter Foo \ println(e.id)

package experiment

trait Entity {
    val id: Option[Long]
}

case class Foo(val id: Option[Long] = None) extends Entity

trait EntityMapper {
    def create[E <: Entity](e: E): E
}

object FooMapper extends EntityMapper {
    def create[Foo](e: Foo): Foo = {
        println(e.id)
        e
    }
}

object Main extends App {
    val foo = FooMapper.create(Foo(None))
}

我尝试了几种不同的方法来解决问题,但没有任何效果。如果我注释掉有问题的行“println(e.id)”,它会编译,但这没有用,因为我无法访问或修改 Foo 的任何属性。

我尝试使用映射器特征的协变参数,然后将类型提供给 FooMapper 对象定义,但这会产生相同的错误。该尝试的代码如下:

trait EntityMapper[+Entity] {
    def create[E <: Entity](e: E): E
}

object FooMapper extends EntityMapper[Foo] {
...
}

我也尝试通过简单继承来实现相同的目标,但我无法正确地将 FooMapper 中的类型参数限制为仅采用 Foos,我必须使方法签名与特征完全匹配,这就是我开始尝试使用实现它的原因具有类型绑定的泛型。该尝试的代码如下:

trait EntityMapper {
    def create(e: Entity): Entity
}

object FooMapper extends EntityMapper {
    def create(e: Foo): Foo = {
        println(e.id)
        e
    }
}

返回的错误码是:

Test.scala:13: 错误:无法创建对象,因为未定义类型 (e:experiment.Entity)experiment.Entity 的 trait EntityMapper 中的方法创建

(注意experiment.Entity不匹配experiment.Foo:包experiment中的类Foo是包experiment中traitEntity的子类,但方法参数类型必须完全匹配。)

object FooMapper extends EntityMapper {
       ^

任何帮助将不胜感激。我使用的是 Scala 版本 2.10.3。

【问题讨论】:

    标签: scala generics type-bounds


    【解决方案1】:

    您可以通过多种方式修复错误

    1.在 trait 上指定泛型类型约束。

    trait EntityMapper[E <: Entity] {
      def create(e: E): E
    }
    
    object FooMapper extends EntityMapper[Foo] {
      def create(e: Foo): Foo = {
        println(e.id)
        e
      }
    }
    

    2.使用参数化类型

    trait EntityMapper {
      type E <: Entity
      def create(e: E): E
    }
    
    object FooMapper extends EntityMapper {
      type E = Foo
      def create(e: Foo): Foo = {
        println(e.id)
        e
      }
    }
    

    查看Scala: Abstract types vs generics 以了解有关这两种方法的更多背景信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-09
      • 2014-06-09
      • 1970-01-01
      • 2016-08-14
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 2013-11-22
      相关资源
      最近更新 更多