Scala:对多态类型的单例实例使用 Nothing
给定一个多态特征,比如
trait Transform[T] { def apply( t: T ) : T }
一个人可能想要实现各种专门的实例,例如
case class Add[Double] extends Transform[Double] { def apply( t: Double ) ... }
case class Append[String] extends Transform[String] { def apply( t: String ) ... }
等等。现在经常需要的转换也是恒等转换。与其为每种类型 T 专门化标识,不如为所有类型 T 只使用一个单例实例。我的问题是:在 Scala 中实现这一目标的最佳方法是什么?
这是我到目前为止发现的内容:查看 List[T] 如何实现 List.empty[T] 和 Nil,我尝试使用 Nothing 作为类型 T。这似乎是有道理的,因为 Nothing 是所有其他类型的子类型:
object Identity extends Transform[Nothing] {
def apply( t: Nothing ) = t
}
这似乎有效。但是,无论我在哪里想要按原样使用此实例,如下所示:
val array = Array[Transform[String]]( Transform.Identity )
我收到编译器错误“类型不匹配;找到:Identity.type,必需:Transform[String]”。为了使用它,我必须显式地转换它:
... Identity.asInstanceOf[Transform[String]]
我不确定这是最好的,甚至是“正确”的方法。感谢您的任何建议。
Given a polymorphic trait like
trait Transform[T] { def apply( t: T ) : T }
one might like to implement various specialized instances, such as
case class Add[Double] extends Transform[Double] { def apply( t: Double ) ... }
case class Append[String] extends Transform[String] { def apply( t: String ) ... }
etc. Now a frequently desired transform is also the identity transform. Instead of specializing identity for each type T, it appears preferable to use just one singleton instance for all types T. My question is: what is the best way to accomplish this in Scala?
Here is what I found so far: looking at how List[T] implements List.empty[T] and Nil, I tried using Nothing as the type T. This seems to make sense, since Nothing is a subtype of every other type:
object Identity extends Transform[Nothing] {
def apply( t: Nothing ) = t
}
This seems to work. However, wherever I then want use this instance as-is, like here:
val array = Array[Transform[String]]( Transform.Identity )
I get the compiler error "type mismatch; found: Identity.type, required: Transform[String]". In order to use it, I have to explicitly cast it:
... Identity.asInstanceOf[Transform[String]]
I am not sure this is the best or even the 'proper' way to do it. Thanks for any advice.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如 @Kim Stebel 指出的那样,您的
Transform[T]
在T
中是不变的(并且必须是因为T
出现在同向和反向中-def apply(t : T) : T)
中的变体位置,因此Transform[Nothing]
不是Transform[String]
的子类型并且不可能成为这样的。如果您主要关心的是每次调用 Kim 的
def Id[A]
时创建实例,那么您最好的模型是 Predef 中的conforms
定义,即。使用多态方法,返回一个转换为适当类型的单例值。这是擦除是胜利的场合之一。
适用于您的情况,我们会有
示例 REPL 会话,
As @Kim Stebel points out your
Transform[T]
is invariant inT
(and has to be becauseT
occurs in both co- and contra- variant positions indef apply(t : T) : T)
soTransform[Nothing]
is not a subtype ofTransform[String]
and can't be made to be.If your main concern is the instance creation on each call of Kim's
def Id[A]
then your best model is the definition ofconforms
in in Predef,ie. use a polymorphic method, returning a singleton value cast to the appropriate type. This is one of occasions where erasure is a win.
Applied to your situation we would have,
Sample REPL session,
由于
Transform[T]
中的类型参数T
是不变的,因此Transform[Nothing]
不是Transform[String] 的子类型
,因此编译器会抱怨它。但在这里使用Nothing
无论如何都是没有意义的,因为永远不可能有Nothing
的实例。那么如何将一个传递给apply
方法呢?你需要再次施放。我能看到的唯一选项是:Since the type parameter
T
inTransform[T]
is invariant,Transform[Nothing]
is not a subtype ofTransform[String]
, thus the compiler complains about it. But usingNothing
here doesn't make sense anyway, since there can never be an instance ofNothing
. So how would you pass one to theapply
method? You would need to cast yet again. The only option I can see is this: