我正在尝试将一堆字符串转换为通用堆栈。
这是Stack of String实现:
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) {}
这是我的Stack of Generic类型实现:
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]) {}
当我尝试使用数据初始化我的新泛型类时:
val generic = new LinkedStackGeneric
generic.push("test")
我收到此语法错误:
type mismatch; found : String("test") required: Nothing
我做错了什么?由于我使用的是类型参数,我不能将任何类型的数据(包括String)添加到方法'push'中吗?
答案 0 :(得分:4)
乍一看,我不指望你想要做什么。
在实例化对象时,类型推断没有基础来推断类型。在下一行中你推动String
是不够聪明的。因此,您必须这样做:
val generic = new LinkedStackGeneric[String]
generic.push("test")
我很想被证明是错的。
答案 1 :(得分:3)
您可以通过使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
答案 2 :(得分:2)
Scala的类型推理引擎因在像你这样的情况下推断Nothing
而臭名昭着。简而言之,Scala的类型层次结构包含顶部(Any
)和底部(Nothing
),其他所有类型之间必须存在。所有类型都有Any
的超类型,Nothing
是所有类型的常见子类型。
这对你意味着什么?好吧,当您实例化LinkedStackGeneric
实例时,省略了类型参数T
的任何类型。这向Scala表明它需要推断类型(因为,作为静态类型语言,它必须在编译时确定所有类型的类型)。在这种情况下,Scala的类型推理引擎选择不佳(从用户期望的角度来看),并选择底部类型(Nothing
)作为参数T
的类型。有了这个,你去添加你的值“test”,Scala编译器(正确地)抱怨String
无法添加到LinkedStackGeneric[Nothing]
,即使所有Nothing
都是是Strings
,并非所有(或可能不是任何)String
都是Nothing
。
好奇的一些笔记。 Nothing
实际上是所谓的无人居住类型,这意味着永远不会存在Nothing
类型的实例。因此,即使我说并非所有String
都是Nothing
s,实际上String
也不可能是Nothing
。