【问题标题】:Scala: Overload (Seq[T]) and (T*)Scala:重载 (Seq[T]) 和 (T*)
【发布时间】:2012-09-20 12:27:17
【问题描述】:

我有一个案例类,以 Seq[T] 作为参数:

case class MyClass(value: Seq[T])

我现在希望能够写作

MyClass(t1,t2,t3)

所以我定义了

object MyClass {
    def apply(value: T*) = new MyClass(value.toSeq)
}

不行,因为case类定义了

object MyClass {
    def apply(value: Seq[T])
}

和Seq[T]和T*擦除后的类型相同,所以不能重载。

但我想允许两种访问方式。两种方式都应该允许:

MyClass(t1,t2,t3)
MyClass(some_seq_of_T)

由于 Seq[T] 和 T* 几乎是同一类型(至少在擦除之后;并且在具有参数 T* 的函数内部变为 Seq[T]),我认为应该有一种方法可以同时允许两种方式调用它。

有吗?

【问题讨论】:

  • 是具体类型还是你的MyClass 有类型参数?

标签: scala types overloading type-erasure


【解决方案1】:

你可以稍微作弊,这样定义你的同伴:

case class MyClass[T](value: Seq[T])

object MyClass {
  def apply[T](first: T, theRest: T*) = new MyClass(first :: theRest.toList)
  def apply[T]() = new MyClass[T](Nil)
}

只要至少有一个参数,第一个apply 就处理MyClass(1,2,3)。 第二个 apply 处理 0 参数的情况。它们不会与常规构造函数冲突。

这样你可以写MyClass(Seq(1,2,3))MyClass(1,2,3)MyClass()。请注意,对于空的,您必须告诉它要返回什么类型,否则它将假定为 MyClass[Nothing]

【讨论】:

  • 这是一个难以理解的黑客攻击。为了什么?为了避免给工厂方法一个不同的名字。
【解决方案2】:

这是没有案例类的解决方案:

scala> class A[T] (ts: Seq[T]) { def this(ts: T*)(implicit m: Manifest[T]) = this(ts) }
defined class A

scala> new A(1)
res0: A[Int] = A@2ce62a39

scala> new A(Seq(1))
res1: A[Seq[Int]] = A@68634baf

【讨论】:

  • 为什么会这样?我认为构造函数的重载方式与问题相同。
  • @Heinzi - 不,还有一个附加参数(隐式)。并且由于隐式在类型擦除之前被解析,编译器能够弄清楚这些东西。
【解决方案3】:

不能有两种同名方法,一种采用Seq[T] 类型的参数,另一种采用T*。编译器如何知道一个调用是否像

val s = Seq(1,2,3) 
foo(s)

应该调用第一种方法或第二种方法(T = Int)或第二种方法(T = Seq[Int])?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多