在Scala中实例化通用类型

时间:2017-11-22 15:35:25

标签: scala

我有一个如下所示的案例类:

case class SomeType[T](x: T)

我现在想通过这样的伴侣对象提供一个空的初始化方法:

object SomeType {
  def empty = SomeType(???)
}

如何实例化泛型类型?我显然不想将它实例化为null或Nill或Any!还有更好的方法吗?

1 个答案:

答案 0 :(得分:3)

您所提问题的问题是SomeType[T]的值x类型为T为空应该x采用什么值?唯一明智的答案是应该是Nothing ,但类型Nothing 无人居住。也就是说,你不能这样做:

def empty[A]: SomeType[A] = SomeType(???)

你不能使x成为一个名字参数(即=> T),因为你有一个案例类(即使你可以,也会很愚蠢,因为有人可以这样做):

val st: SomeType[Int] = SomeType.empty //would require T to be covariant
val i = st.x //throws Exception

让我们退后一步,不用x开始:

sealed trait SomeType[T]
object SomeType {
  def empty[A]: SomeType[A]          = new SomeType[A] {}
  def nonEmpty[A](a: A); SomeType[A] = new SomeType[A] {}
} 

如果你正在建模有点像Option的东西,那么值得思考它应该具备的基本组合器是什么。这是编码Option的一种方法,例如:

sealed trait MyOption[T] {

  def fold[B](n: => B, s: T => B): B //fundamental combinator

  //functionality
  import MyOption._
  final def isEmpty                                      = fold(true, _ => false)
  final def flatMap[B](f: A => MyOption[B]): MyOption[B] = fold(empty, f)
  final def map[B](f: A => B): MyOption[B]               = fold(empty, f andThen nonEmpty)
}

object MyOption {
  //These are effectively the constructors
  def empty[A]: MyOption[A] = new MyOption[A] {
    override final def fold[B](n: => B, s: A => B): B = n 
  }
  def nonEmpty[A](a: A): MyOption[A] = new MyOption[A] {
    override final def fold[B](n: => B, s: A => B): B = s(a) 
  }
} 

您可以使其协变并使empty成为val

sealed trait MyOption[+T] {
  def fold[B](n: => B, s: T => B): B
}
object MyOption {
  val empty: MyOption[Nothing] = new MyOption[Nothing] {
    override final def fold[B](n: => B, s: Nothing => B): B = n 
  }
  def nonEmpty[A](a: A): MyOption[A] = new MyOption[A] {
    override final def fold[B](n: => B, s: A => B): B = s(a) 
  }
} 

或者如下面的 Yuval 所示,将empty设为单身:

object MyOption {
  object empty extends MyOption[Nothing] {
    override final def fold[B](n: => B, s: Nothing => B): B = n 
  }
  def nonEmpty[A](a: A): MyOption[A] = new MyOption[A] {
    override final def fold[B](n: => B, s: A => B): B = s(a) 
  }
} 

我通常不喜欢这样做,因为我宁愿使用组合器而不是显式模式匹配,这不太适合重构