通用类型,这样一个方法的结果可以再次用作另一个方法的参数
Generic typing so that one method's result can be used as other method's parameter again
我的代码归结为工厂初始化对象,然后再次使用该对象执行其他操作:
trait Factory[T] {
def initialize(): T;
def finish(t: T): Unit;
}
据我了解,对于任何一个 Factory
实例,initialize
的结果应该始终适合传递给 finish
,而不考虑 T
。
工厂本身在不知道 T
是什么的地方被调用:
object Minimal {
object StringFactory extends Factory[String] {}
val factories = Map[Int, Factory[_]](0 -> StringFactory)
val factory = factories(0)
// (1)
val obj = factory.initialize()
factory.finish(obj)
// (2)
def wrapper[T](factory: Factory[T]): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}
变体 (2) 有效,变体 (1) 无效:
type mismatch; found : Minimal.obj.type (with underlying type Any) required: _
但我不知道如何解决这个问题。有可能吗?
编译器调用自己搞不清楚的wrapper
方法得到了什么?在我看来,obj
的类型应该是 _
,因为编译器似乎命名了 _
的捕获。我怎样才能让编译器意识到这一点而不必为其引入一个全新的方法?
存在类型在将其实例分配给 val 本身后失去其存在性并成为上限,因此任何不进行此类分配的方式都可以工作,包括:
scala> trait Factory[T] { type TT = T; def initialize(): TT; def finish(t: TT): Unit;}
defined trait Factory
scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
factory: Factory[_] = $anon@31d0ca61
scala> factory.finish(factory.initialize())
这行不通:
scala> val obj = factory.initialize()
obj: Any = 5
scala> factory.finish(obj)
<console>:11: error: type mismatch;
found : Any
required: factory.TT
(which expands to) _
factory.finish(obj)
^
这是因为 scala 不会将它们的类型视为相等(除非两者是同一类型的成员),因为存在性意味着 intialize()
可以 return Any 的任何子类,当 finish()
可以接受 Any:
的任何(但不总是相同的)子类
scala> trait Factory[T] { def initialize(): T; def finish(t: T): Unit;}
defined trait Factory
scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
factory: Factory[_] = $anon@6e5da49
scala> factory.finish(factory.initialize())
<console>:10: error: type mismatch;
found : (some other)_(in value factory)
required: _(in value factory)
factory.finish(factory.initialize())
^
所以在这里绑定输入和输出的唯一方法是在它们之间共享类型成员。
一个解决方案是用抽象类型完全替换类型参数:
trait Factory {
type T
def initialize(): T;
def finish(t: T): Unit;
}
object Minimal {
object StringFactory extends Factory {
type T = String
def initialize(): T = ???
def finish(t: T): Unit = ???
}
val factories = Map[Int, Factory](0 -> StringFactory)
val factory: Factory = factories(0)
// (1)
val obj: factory.T = factory.initialize()
// Or simply (relying on inference): val obj = factory.initialize()
factory.finish(obj)
// (2)
def wrapper(factory: Factory): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}
基于 Régis 的 , I found out that the compiler infers obj: Factory.T
. From there, it was a small step to combine this with dk14's 使用 type TT = T
。结果是这样的,但是是通用的和静态类型检查的,没有引入包装器方法。向两位致敬!
从字面上回答原问题
From my point of view, obj's type should be _, as the compiler seems to name that capture of _. How can I make the compiler realize that without having to introduce a whole new method for it?
通过给 _
显式名称 TT
。当然,这些方法也需要使用该名称。
trait Factory[T] {
type TT = T
def initialize(): TT;
def finish(t: TT): Unit;
}
object Minimal {
object StringFactory extends Factory[String] {
def initialize(): TT = ""
def finish(t: TT): Unit = {}
}
val factories = Map[Int, Factory[_]](0 -> StringFactory)
val factory = factories(0)
// (1)
val obj: factory.TT = factory.initialize()
factory.finish(obj)
// (2)
def wrapper[T](factory: Factory[T]): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}
我的代码归结为工厂初始化对象,然后再次使用该对象执行其他操作:
trait Factory[T] {
def initialize(): T;
def finish(t: T): Unit;
}
据我了解,对于任何一个 Factory
实例,initialize
的结果应该始终适合传递给 finish
,而不考虑 T
。
工厂本身在不知道 T
是什么的地方被调用:
object Minimal {
object StringFactory extends Factory[String] {}
val factories = Map[Int, Factory[_]](0 -> StringFactory)
val factory = factories(0)
// (1)
val obj = factory.initialize()
factory.finish(obj)
// (2)
def wrapper[T](factory: Factory[T]): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}
变体 (2) 有效,变体 (1) 无效:
type mismatch; found : Minimal.obj.type (with underlying type Any) required: _
但我不知道如何解决这个问题。有可能吗?
编译器调用自己搞不清楚的wrapper
方法得到了什么?在我看来,obj
的类型应该是 _
,因为编译器似乎命名了 _
的捕获。我怎样才能让编译器意识到这一点而不必为其引入一个全新的方法?
存在类型在将其实例分配给 val 本身后失去其存在性并成为上限,因此任何不进行此类分配的方式都可以工作,包括:
scala> trait Factory[T] { type TT = T; def initialize(): TT; def finish(t: TT): Unit;}
defined trait Factory
scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
factory: Factory[_] = $anon@31d0ca61
scala> factory.finish(factory.initialize())
这行不通:
scala> val obj = factory.initialize()
obj: Any = 5
scala> factory.finish(obj)
<console>:11: error: type mismatch;
found : Any
required: factory.TT
(which expands to) _
factory.finish(obj)
^
这是因为 scala 不会将它们的类型视为相等(除非两者是同一类型的成员),因为存在性意味着 intialize()
可以 return Any 的任何子类,当 finish()
可以接受 Any:
scala> trait Factory[T] { def initialize(): T; def finish(t: T): Unit;}
defined trait Factory
scala> val factory: Factory[_] = new Factory[Int] {def initialize = 5; def finish(t: Int) {}}
factory: Factory[_] = $anon@6e5da49
scala> factory.finish(factory.initialize())
<console>:10: error: type mismatch;
found : (some other)_(in value factory)
required: _(in value factory)
factory.finish(factory.initialize())
^
所以在这里绑定输入和输出的唯一方法是在它们之间共享类型成员。
一个解决方案是用抽象类型完全替换类型参数:
trait Factory {
type T
def initialize(): T;
def finish(t: T): Unit;
}
object Minimal {
object StringFactory extends Factory {
type T = String
def initialize(): T = ???
def finish(t: T): Unit = ???
}
val factories = Map[Int, Factory](0 -> StringFactory)
val factory: Factory = factories(0)
// (1)
val obj: factory.T = factory.initialize()
// Or simply (relying on inference): val obj = factory.initialize()
factory.finish(obj)
// (2)
def wrapper(factory: Factory): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}
基于 Régis 的 obj: Factory.T
. From there, it was a small step to combine this with dk14's type TT = T
。结果是这样的,但是是通用的和静态类型检查的,没有引入包装器方法。向两位致敬!
从字面上回答原问题
From my point of view, obj's type should be _, as the compiler seems to name that capture of _. How can I make the compiler realize that without having to introduce a whole new method for it?
通过给 _
显式名称 TT
。当然,这些方法也需要使用该名称。
trait Factory[T] {
type TT = T
def initialize(): TT;
def finish(t: TT): Unit;
}
object Minimal {
object StringFactory extends Factory[String] {
def initialize(): TT = ""
def finish(t: TT): Unit = {}
}
val factories = Map[Int, Factory[_]](0 -> StringFactory)
val factory = factories(0)
// (1)
val obj: factory.TT = factory.initialize()
factory.finish(obj)
// (2)
def wrapper[T](factory: Factory[T]): Unit = {
val obj = factory.initialize()
factory.finish(obj)
}
wrapper(factory)
}