我的代码可归结为Factory初始化对象,然后再次使用该对象执行其他操作:
trait Factory[T] {
def initialize(): T;
def finish(t: T): Unit;
}
据我了解,initialize
的结果应始终适合传递给finish
任何一个Factory
实例,而不管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: _$6
但我无法弄清楚如何解决这个问题。它甚至可能吗?
编译器通过调用它无法弄清楚的wrapper
方法获得了什么?从我的角度来看,obj
的类型应该是_$6
,因为编译器似乎将_
的捕获命名为。如何让编译器意识到这一点,而不必为它引入一个全新的方法?
答案 0 :(得分:3)
存在类型在将其实例赋值给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$1@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) _$1
factory.finish(obj)
^
这是因为scala不会将它们的类型视为相等(除非两者都是同一类型的成员),因为存在性意味着intialize()
可能会返回Any的任何子类,而finish()
可能会接受任何({1}}并不总是相同的)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$1@6e5da49
scala> factory.finish(factory.initialize())
<console>:10: error: type mismatch;
found : (some other)_$1(in value factory)
required: _$1(in value factory)
factory.finish(factory.initialize())
^
因此,绑定输入和输出的唯一方法是在它们之间共享类型成员。
答案 1 :(得分:2)
一种解决方案是用抽象类型完全替换type参数:
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)
}
答案 2 :(得分:1)
基于Régis'answer,我发现编译器推断obj: Factory.T
。从那里开始,将它与dk14的suggestion结合使用type TT = T
是一小步。结果是这个,但是通用和静态类型检查,没有引入包装器方法。感谢两者!
完全回答原始问题
从我的观点来看,obj的类型应该是_ $ 6,因为编译器似乎将_的捕获命名为。如何让编译器意识到这一点,而不必为它引入一个全新的方法?
为_$6
提供明确的名称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)
}