将Scala结构类型与抽象类型一起使用

时间:2010-04-28 01:57:04

标签: scala structural-typing

我正在尝试定义一个结构类型,定义任何具有“add”方法的集合(例如,java集合)。使用这个,我想定义一些在某个集合上运行的高阶函数

object GenericTypes {
  type GenericCollection[T] = { def add(value: T): java.lang.Boolean}
}

import GenericTypes._
trait HigherOrderFunctions[T, CollectionType[X] <: GenericCollection[X]] {
    def map[V](fn: (T) => V): CollectionType[V]
    ....
}

class RichJList[T](list: List[T]) extends HigherOrderFunctions[T, java.util.List]

这不会编译时出现以下错误

error: Parameter type in structural refinement may not refer to abstract type defined outside that same refinement 

我尝试删除GenericCollection上的参数并将其放在方法上:

object GenericTypes {
  type GenericCollection = { def add[T](value: T): java.lang.Boolean}
}
import GenericTypes._
trait HigherOrderFunctions[T, CollectionType[X] <: GenericCollection]

class RichJList[T](list: List[T]) extends HigherOrderFunctions[T, java.util.List]

但我收到另一个错误:

error: type arguments [T,java.util.List] do not conform to trait HigherOrderFunctions's type parameter bounds [T,CollectionType[X] <: org.scala_tools.javautils.j2s.GenericTypes.GenericCollection]

有人可以给我一些关于如何在Scala中使用抽象类型参数进行结构化输入的建议吗?或者如何实现我想要实现的目标?非常感谢!

1 个答案:

答案 0 :(得分:4)

正如您在ticket 1906中看到的那样,由于在运行时缺少类型信息,因此无法使用结构类型之外定义的抽象类型。

这在Scala Language Reference (3.2.7 Compound Types)

中说明
Within a method declaration in a structural refinement, the type of
any value parameter may only refer to type parameters or abstract types that are
contained inside the refinement.

向类型添加新方法的常用方法是通过隐式类型转换。

trait HigherOrderFunctions[T, CC[_]] {
    def zap[V](fn: () => V): CC[V]
}

class RichJList[T](list: java.util.List[T]) extends HigherOrderFunctions[T, java.util.List]{
    def zap[V](fn: () => V): java.util.List[V] = {
        val l = new java.util.ArrayList[V]
        l add fn()
        l
    }
}
implicit def list2RichList[T](l : java.util.List[T]) = new RichJList(l)
new java.util.ArrayList[AnyRef]() zap (() => 2)

如果编译器发现该类型错过了zap方法,它会将其转换为具有zap方法的类型,该方法在范围内具有隐式转换方法(此处为list2RichList)。

scala> new java.util.ArrayList[AnyRef]() zap (() => 2)
res0: java.util.List[Int] = [2]