Scala:对多态类型的单例实例使用 Nothing

发布于 2024-12-08 01:17:56 字数 938 浏览 0 评论 0原文

给定一个多态特征,比如

 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜嗑 2024-12-15 01:17:56

正如 @Kim Stebel 指出的那样,您的 Transform[T]T 中是不变的(并且必须是因为 T 出现在同向和反向中- def apply(t : T) : T) 中的变体位置,因此 Transform[Nothing] 不是 Transform[String] 的子类型并且不可能成为这样的。

如果您主要关心的是每次调用 Kim 的 def Id[A] 时创建实例,那么您最好的模型是 Predef 中的 conforms 定义,

private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

即。使用多态方法,返回一个转换为适当类型的单例值。这是擦除是胜利的场合之一。

适用于您的情况,我们会有

object SingletonId extends Transform[Any] { def apply(t : Any) = t }
def Id[A] = SingletonId.asInstanceOf[Transform[A]]

示例 REPL 会话,

scala> Id("foo")
res0: java.lang.String = foo

scala> Id(23)
res1: Int = 23

As @Kim Stebel points out your Transform[T] is invariant in T (and has to be because T occurs in both co- and contra- variant positions in def apply(t : T) : T) so Transform[Nothing] is not a subtype of Transform[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 of conforms in in Predef,

private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

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,

object SingletonId extends Transform[Any] { def apply(t : Any) = t }
def Id[A] = SingletonId.asInstanceOf[Transform[A]]

Sample REPL session,

scala> Id("foo")
res0: java.lang.String = foo

scala> Id(23)
res1: Int = 23
不交电费瞎发啥光 2024-12-15 01:17:56

由于 Transform[T] 中的类型参数 T 是不变的,因此 Transform[Nothing] 不是 Transform[String] 的子类型,因此编译器会抱怨它。但在这里使用 Nothing 无论如何都是没有意义的,因为永远不可能有 Nothing 的实例。那么如何将一个传递给 apply 方法呢?你需要再次施放。我能看到的唯一选项是:

scala> def Id[A] = new Transform[A] { override def apply(t:A) = t }
Id: [A]=> java.lang.Object with Transform[A]

scala> Id(4)
res0: Int = 4

scala> Id("")
res1: java.lang.String = ""

Since the type parameter T in Transform[T] is invariant, Transform[Nothing] is not a subtype of Transform[String], thus the compiler complains about it. But using Nothing here doesn't make sense anyway, since there can never be an instance of Nothing. So how would you pass one to the apply method? You would need to cast yet again. The only option I can see is this:

scala> def Id[A] = new Transform[A] { override def apply(t:A) = t }
Id: [A]=> java.lang.Object with Transform[A]

scala> Id(4)
res0: Int = 4

scala> Id("")
res1: java.lang.String = ""
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文