3

我正在尝试将一堆 Strings 转换为通用 Stack 。

这是字符串实现的堆栈:

class LinkedStackOfStrings {

  var first : Node = _

  def isEmpty : Boolean  = {
    first == null
  }

  def push(itemName : String) = {
    val oldFirst = first
    first = new Node(itemName , oldFirst)
  } 

  def pop = {
    first = first.next

    first.itemName

  }

}

  class Node(val itemName : String , val next : Node) {}

这是我的通用类型堆栈实现:

class LinkedStackGeneric[T] {

  var first : NodeGeneric[T] = _

  def isEmpty : Boolean  = {
    first == null
  }

  def push(itemName : T) = {
    val oldFirst = first
    first = new NodeGeneric(itemName , oldFirst)
  } 

  def pop = {
    first = first.next

    first.itemName

  }

}

  class NodeGeneric[T](val itemName : T , val next : NodeGeneric[T]) {}

当我尝试用 data 初始化我的新泛型类时:

   val generic = new LinkedStackGeneric
   generic.push("test")

我收到此语法错误:

type mismatch; found : String("test") required: Nothing

我究竟做错了什么 ?由于我使用的是类型参数,我是否应该无法将包括 String 在内的任何类型的数据添加到方法 'push' 中?

4

3 回答 3

4

乍一看,我没想到你正在努力工作。

类型推断没有在实例化对象时推断类型的基础。在下一行看到你按下 . 是不够聪明的String。因此,您必须这样做:

val generic = new LinkedStackGeneric[String]
generic.push("test")

我很想被证明是错误的。

于 2013-04-17T20:27:04.370 回答
4

您可以通过使Stack对象不可变来解决此问题:

object ImmutableStack {
  trait ImmutableStack[+A] {
    def isEmpty: Boolean
    def push[B >: A](item: B): ImmutableStack[B] = new <<(this, item)
    def pop: (ImmutableStack[A], Option[A])
    def <<[B >: A](item: B) = push(item)
  }
  case class <<[+A](init: ImmutableStack[A], last: A) extends ImmutableStack[A] {
    override def isEmpty = false
    override def pop: (ImmutableStack[A], Option[A]) = (init, Some(last))
    override def toString = "" + init + " << " + last
  }
  case object Nst extends ImmutableStack[Nothing] {
    override def isEmpty = true
    override def pop = (Nst, None)
    override def toString = "Nst"
  }
}

然后我们有:

scala> import ImmutableStack._
import ImmutableStack._

scala> val intStack = Nst << 5 << 4 << 3 << 2 << 1
intStack: ImmutableStack.ImmutableStack[Int] = Nst << 5 << 4 << 3 << 2 << 1

scala> intStack.pop
res0: (ImmutableStack.ImmutableStack[Int], Option[Int]) = (Nst << 5 << 4 << 3 << 2,Some(1))

scala> val firstItems << lastItem = intStack
firstItems: ImmutableStack.ImmutableStack[Int] = Nst << 5 << 4 << 3 << 2
lastItem: Int = 1

scala> val strStack = Nst << "A" << "B" << "C"
strStack: ImmutableStack.ImmutableStack[String] = Nst << A << B << C

scala> val fs << lt = strStack
fs: ImmutableStack.ImmutableStack[String] = Nst << A << B
lt: String = C

scala> val anyStack = Nst << 1 << "Str" << 'Z'
anyStack: ImmutableStack.ImmutableStack[Any] = Nst << 1 << Str << Z


scala> val st << x1 << x2 << x3 = anyStack
st: ImmutableStack.ImmutableStack[Any] = Nst
x1: Any = 1
x2: Any = Str
x3: Any = Z
于 2013-04-18T02:26:55.207 回答
2

NothingScala 的类型推理引擎因在像您这样的情况下进行推理而臭名昭著。简而言之,Scala 的类型层次结构既有顶部 ( Any) 也有底部 ( Nothing),所有其他类型都必须存在于它们之间。所有类型都有一个超类型Any, 并且Nothing是所有类型的公共子类型。

这对你意味着什么?好吧,当你实例化你的LinkedStackGeneric实例时,你省略了类型参数的任何类型T。这向 Scala 表明它需要推断类型(因为作为静态类型语言,它必须在编译时确定所有内容的类型)。在这种情况下,Scala 的类型推理引擎选择不佳(从用户期望的角度来看),并选择底部类型 ( Nothing) 作为参数的类型T。有了这个,你去添加你的值“测试”,Scala编译器(正确地)抱怨String不能添加到 a LinkedStackGeneric[Nothing],因为即使所有Nothings 都是 s Strings,但并非所有(或可能不是任何)Strings 都是Nothings 。

为好奇的人提供更多注意事项。Nothing实际上是所谓的无人居住类型,这意味着永远不会有 type 的实例Nothing。所以,即使我说不是所有String的 s 都是Nothings,实际上 a 不可能String是 a Nothing

于 2013-04-17T20:49:02.590 回答