为什么 Scala 辅助构造函数中不允许使用类型参数?

发布于 2024-12-03 04:15:02 字数 530 浏览 0 评论 0原文

假设我正在 Scala 中定义一个简单的 2D 点类,并且我希望能够使用各种类型来构造它:

class Point(x:Float, y:Float) {
    this(x:Double, y:Double) = this(x.toFloat, y.toFloat)
    this(x:Int, y:Int) = this(x.toFloat, y.toFloat)
    // etc...
}

我想使用模板将其归结为以下内容:

class Point(x:Float, y:Float) {
    this[T](x:T, y:T) = this(x.toFloat, y.toFloat)
}

我知道这无论如何都行不通,因为 T可能是未定义 toFloat 的类型,但我得到的编译器错误是:

此处不允许使用类型参数

这是 Scala 不支持的吗?如果是这样,为什么,有什么简单的方法可以解决这个问题吗?

Say I'm defining a simple 2D point class in Scala, and I want to be able to construct it with various types:

class Point(x:Float, y:Float) {
    this(x:Double, y:Double) = this(x.toFloat, y.toFloat)
    this(x:Int, y:Int) = this(x.toFloat, y.toFloat)
    // etc...
}

I want to boil this down using a template, such as:

class Point(x:Float, y:Float) {
    this[T](x:T, y:T) = this(x.toFloat, y.toFloat)
}

I know this won't work anyway, since T could be a type for which toFloat isn't defined, but the compiler error I get is:

no type parameters allowed here

Is this just unsupported in Scala? If so, why, and is there any simple way to get around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

空城仅有旧梦在 2024-12-10 04:15:02

Scala 的类构造函数(与 Java 不同)不能采用类型参数,只有类本身可以。至于为什么 Scala 做出这样的设计选择,我认为主要原因是简单。

如果您想要一个通用的辅助“构建器”方法,那么自然要做的就是在伴随对象上定义它。例如,

object Point {
  def build[T : Numeric](x: T, y: T) = {
    val n = implicitly[Numeric[T]]
    new Point(n.toFloat(x), n.toFloat(y))
  }
}

class Point(val x:Float, val y:Float)

val p = Point.build(1, 2) // Companion object's builder
p.x + p.y

这里我使用 Numeric 类型类来获取通用 toFloat 方法。

Scala's class constructors (unlike Java's) can't take type parameters, only the class itself can. As to why Scala made this design choice, I assume the main reason is simplicity.

If you want a secondary "builder" method that is generic, the natural thing to do is define it on the companion object. For example,

object Point {
  def build[T : Numeric](x: T, y: T) = {
    val n = implicitly[Numeric[T]]
    new Point(n.toFloat(x), n.toFloat(y))
  }
}

class Point(val x:Float, val y:Float)

val p = Point.build(1, 2) // Companion object's builder
p.x + p.y

Here I've used the Numeric typeclass to get a generic toFloat method.

拒绝两难 2024-12-10 04:15:02

我玩了一段时间,变得“接近”...

class Point(x:Float, y:Float) {
  def this[T <: Any { def toFloat: Float }](x:T, y:T) = this(x.toFloat, y.toFloat)
}

...这导致“错误:此处不允许类型参数”(正如帖子所述),然后我意识到...

如果初始化器可以采用类型参数,如果有的话,它与类参数会产生歧义。并不是说这个不能在语言规范中解决......但它是一个更复杂的至少是这样的情况。还可能存在 Java 互操作性问题。

想象一下:

class Foo[T](x: T) {
   def this[X](z: X) = ...
}
new Foo[Int](42) // T is Int? X is ...? Or ...?

我个人希望 Scala 遵循类似 Eiffel 的模式(仅命名构造函数或“工厂方法”),但可惜,这不是 Scala。

快乐编码。

I played with this for awhile, getting as "close" as...

class Point(x:Float, y:Float) {
  def this[T <: Any { def toFloat: Float }](x:T, y:T) = this(x.toFloat, y.toFloat)
}

...which results in "error: no type parameters allowed here" (just as per the post) and then I realized...

If the initializer could take type parameters it would be ambiguous with the class parameters, if any. Not that this couldn't be worked about in the language specification... but it is a more complex case at the very least. There might also be Java interoperability issues.

Imagine:

class Foo[T](x: T) {
   def this[X](z: X) = ...
}
new Foo[Int](42) // T is Int? X is ...? Or ...?

Personally I wish Scala followed an Eiffel-like pattern (only named constructors or "factory methods"), but alas, that would not be Scala.

Happy coding.

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