在this tutorial中完成Scala高级类型的一些示例之后,我开始想知道是否有可能编写一个通常处理特征的两个子类的方法 被定义为更高级的类型。
本教程定义了这个特性的一个稍微复杂的版本:
trait ContainerFactory[M[_]] { def put[A](x: A): M[A] }
我理解为类型参数化工厂的签名,它创建了不同类型的容器(Lists
,Set
等,其中容器的类型由M
给出并且A
给出了通过put方法插入容器的对象类型的位置。在你所在的调用网站(我认为这是正确的术语)
实例化容器,指定所需容器的类型(如注释中所示://factory for List containers)
val factory = new ContainerFactory[List] { def put[A](x: A) = List(x) } // factory for List containers
factory.put("dog") // insert an element of type String to factory
res5: List[String] = List(dog) // and you get a List of String
factory.put(1)// insert an element of type Int to factory
res6: List[Int] = List(1) // and you get a List of Int
val factory2 = new ContainerFactory[Set] { def put[A](x: A) = Set(x)} // factory for Set containers
factory2.put("dog")
factory2.put(1)
我的目标是创建一个采用ContainerFactory
的方法
以及放入生成的容器的对象。我希望该方法生成适当的容器(List
或Set
)参数化,以保存我作为第二个对象传入的对象类型。
我认为像下面这样的方法真的很酷且很有用,但是我在使用Scala语法时遇到了麻烦。事实上,我甚至不知道是否可能。
// Code below does not compile
// Method for generating container (of type defined by first arg) that contains the second argument, and
// which (after instantiation) is parameterized to hold only objects of that type:
def genContainer[M[T]](factory: ContainerFactory[M], item : T) = {
factory.put(item)
}
genContainer(factory2, "x")
// desired return value => Set[String] = Set(x)
genContainer(factory, 11)
// desired return value => List[Int] = List(11)
注意:我尝试定义genContainer
时收到的错误是:
<console>:10: error: not found: type T
def genContainer[M[T]]( factory : Container[M] , item : T) = {
注2:我可以定义一个这样的方法,它采用通用的ContainerFactory
def genContainer[M[T]](factory: ContainerFactory[M]) = { }
但是当我尝试将第二个参数指定为类型T
(在参数化中引用)时,我得到关于T
未找到的错误。
答案 0 :(得分:2)
你非常接近。问题是您需要单独声明类型参数:
def genContainer[T, M[_]](factory: ContainerFactory[M], item: T) =
factory.put(item)
这有点令人困惑,因为以下编译:
def genContainer[M[T]](factory: ContainerFactory[M]) = "whatever"
此处T
的范围仅限于M[...]
的内部(有关详细信息,请参阅the language specification的第4.4节)。当您声明像M[T <: Foo[T]]
这样的花哨边界时,这很方便,但通常给出类型构造函数的类型参数名称只是噪声,最好使用M[_]
(这正是相当于M[A]
)。
答案 1 :(得分:1)
你真的很亲密:
def genContainer[T, M[_]](factory: ContainerFactory[M], item: T) = {
factory.put(item)
}
您所要做的就是将每个类型参数指定为顶级类型参数!并且编译器足够聪明,可以在许多情况下推导出这些类型参数:
val factory = new ContainerFactory[List] { def put[A](x: A) = List(x) }
genContainer(factory, "foo") //No need to specify the type parameters!