Using Scala structural types with abstract types

余生长醉 提交于 2019-12-04 18:45:42

问题


I'm trying to define a structural type defining any collection that has an "add" method (for instance, a java collection). Using this, I want to define a few higher order functions that operate on a certain collection

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]

This does not compile with the following error

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

I tried removing the parameter on GenericCollection and putting it on the method:

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]

but I get another error:

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]

Can anyone give me some advice on how to use structural typing with abstract typed parameters in Scala? Or how to achieve what I'm looking to accomplish? Thanks so much!


回答1:


As you can see in ticket 1906 you can't use the abstract type defined outside the structural type due to missing type information at runtime.

This is stated in the 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.

The usual way to add new methods to a type is by implicit type conversion.

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)

If the compiler sees that the type missed the zap method it will convert it to a type that has the zap method with a implicit conversion method (here list2RichList) in scope.

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


来源:https://stackoverflow.com/questions/2726364/using-scala-structural-types-with-abstract-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!