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

问题描述:

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

Test.scala:15:错误:值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)) 
} 

我已经尝试了几种不同的东西来解决类型参数的Foo \ 的println(e.id)的成员问题,但没有任何工作。如果我注释掉问题行“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:错误:对象创建不可能的,因为在方法类型的性状EntityMapper(例如创建:实验。 Entity)experiment.Entity is not defined

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

object FooMapper extends EntityMapper { 
    ^

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

您可以在几个方面

  1. 指定的特质泛型类型约束修正这个错误。

    性状EntityMapper [E <:实体] { DEF创建(E:E):电子 }

    对象FooMapper延伸EntityMapper [美孚] { DEF创建(例如:富):富= { 的println(E。ID) Ë } }

  2. 使用参数化的类型

    性状EntityMapper { 类型E <:

    对象FooMapper延伸EntityMapper {Ê }:实体 DEF创建(E:E) type E = Foo def create(e:Foo):Foo = { println(e.id) e } }

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