如何使用具有通用参数的结构类型?

时间:2013-03-24 13:02:32

标签: scala generics structural-typing

我有两个案例类

case class StringCaseClass(argument: String)

case class IntCaseClass(argument: Int)

我想定义一个结构类型,它将匹配这两个

的伴随对象
type HasApply1 {
  def apply[A, R](argument: A): R
}

这将编译正常,但当我尝试像这样使用它

def method(caseClass: HasApply1) {
  // whatever
}

method(StringCaseClass)

我会收到编译错误

found   : StringCaseClass.type
required: WithApply1
            (which expands to)  AnyRef{def apply[A, R](string: A): R}

有没有办法实现这个目标?如果我重新定义结构类型以获得A和R的具体类型,它将正确编译,但后来我失去了灵活性

3 个答案:

答案 0 :(得分:9)

@ aloiscochard的评论几乎就在那里。他忘记提到的是案例类伴侣对象已经实现了相应的FunctionN特征,所以你可以简单地做到这一点,

scala> case class StringCaseClass(argument: String)
defined class StringCaseClass

scala> case class IntCaseClass(argument: Int)
defined class IntCaseClass

scala> def method[A, R](caseClass: A => R, a: A) = caseClass(a)
method: [A, R](caseClass: A => R, a: A)R

scala> method(StringCaseClass, "foo")
res0: StringCaseClass = StringCaseClass(foo)

scala> method(IntCaseClass, 23)
res1: IntCaseClass = IntCaseClass(23)

答案 1 :(得分:3)

一般来说,你应该避免使用结构类型,因为它非常昂贵。由于JVM的限制,调用将转换为反射调用。当您开始使用scala 2.10时,结构类型将在编译时产生警告(尽管您可以使用标志禁用它)。

如果您正在研究一种更通用的方法来为不共享继承层次结构的类添加功能,那么可以使用Type Classes。

这是一个简单的例子:

trait CanCreateRFromA[A,R]{
    def createNew(a:A): R
}

implicit object CanCreateBlahFromInt extends CanCreateRFromA[Int,Blah2]{
    def createNew(i:Int):Blah2 = new Blah2(i)
}


implicit object CanCreateBlah1FromString extends CanCreateRFromA[String,Blah1]{
    def createNew(s:String):Blah1 = new Blah1(s)
}

case class Blah1(something:String)
case class Blah2(something:Int)

def createRFromA[A,R](a:A)(implicit tc:CanCreateRFromA[A,R])= tc.createNew(a)

然后你可以打电话:

createRFromA(1) // This gives a Blah2
createRFromA("1") // This gives a Blah1

同样,我不确定你要完成什么,但它可能可以用类型类做你想做的事情,它会更快。

答案 2 :(得分:0)

您未将StringCaseClass的实例传递给method。你在那里传递的是StringCaseClass的伴随对象(它是为案例类自动生成的)。

尝试这是否有效:method(StringCaseClass("dummy"))