Scala中构造函数的通用参数

4
考虑以下人为的Java示例:
public class Example {

    private final Object value;
    private final List<?> aListOfTheseThings;

    public <T> Example(final T t, final List<T> aListOfTheseThings) {
        this.value = t;
        this.aListOfTheseThings = aListOfTheseThings;
    }

}

在这个例子中,我关心的内容如下:

  1. Example没有进行参数化
  2. 构造函数已经进行了参数化,并确保无论您传入什么,列表都是用与t相同类型进行参数化的

(这只是一个假想的例子,我并不真正关心(2),但我确实很关心在类的定义中没有提及的类型参数)。

现在在Scala中,我尝试了以下操作:

class Example private[this](
  private val value: AnyRef,
  private val aListOfTheseThings: List[_]) {

  def this[T](t: T, aListOfTheseThings: List[T]) {
    this(t, aListOfTheseThings)
  }
}

然而这是不可能的。显然,类型参数在构造函数中是无效的(在this中)。

有没有可能将上述Java代码翻译成Scala?


1
在伴生对象中加入一个 apply[T] 工厂方法怎么样? - Seth Tisue
2个回答

8
或许这可以帮到您:
sealed trait Example

object Example {
  def apply[T <: AnyRef](t:T, aListOfTheseThings: List[T]): Example = 
    new ExampleImpl(t, aListOfTheseThings)

  private class ExampleImpl(
    val value: AnyRef, 
    val aListOfTheseThings: List[_]) extends Example 
}

这使得Example类的私有构造函数、value以及aListOfTheseThings不能通过Example特质来访问(除非你将其设置为可访问)。

谢谢。我在想,如果现在我想要子类化,比如 class AnEvenMoreContrivedExample extends Example("a thing", List("some", "things")),它会是怎样的工作方式。 - scravy

7
Nyavro提出的helper的apply方法是一个很好的建议。在某些情况下,另一种适当的选择是子类化:
trait Example {
  val value: Any
  val things: List[_]
}

class SameTypeExample[T](val value: T, val things: List[T]) extends Example

子类化的优点在于,valuethings存储相同类型的约束条件不会丢失,并且可以通过模式匹配重新发现:
def handle(example: Example) = example match {
  case st: SameTypeExample[t] =>
    st.value :: st.things    
}   

子类化是Scala中的一种通用技术,用于在构造时暂时隐藏信息。


我喜欢子类化的方法,但是apply()方法已经解决了我的问题 :-) 这就是为什么我接受了另一个Nyavro的答案。 - scravy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接