首页 文章

在Scala中使用泛型实现特征的正确方法是什么?

提问于
浏览
1

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

Test.scala:15:错误:值id不是类型参数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的任何属性 .

我已经尝试对mapper trait使用covariant参数,然后将类型提供给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:错误:对象创建不可能,因为方法在特性EntityMapper中创建了类型(e:experiment.Entity)experiment.Entity未定义

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

object FooMapper extends EntityMapper {
       ^

任何帮助将不胜感激 . 我正在使用Scala版本2.10.3 .

1 回答

  • 3

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

    1.在特征上指定泛型类型约束 .

    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以获得有关这两种方法的更多背景信息 .

相关问题