3

String のスタックをジェネリック 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]) {}

新しいジェネリック クラスをデータで初期化しようとすると、次のようになります。

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

次の構文エラーが表示されます。

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

私は何を間違っていますか?型パラメーターを使用しているため、String を含む任意の型のデータをメソッド 'push' に追加することはできませんか?

4

3 に答える 3

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 に答える
4

一見すると、あなたがやろうとしていることは期待できません。

型推論には、オブジェクトをインスタンス化するときに型を推論する根拠がありません。次の行でString. その結果、これを行う必要があります。

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

私が間違っていると証明されたいです。

于 2013-04-17T20:27:04.370 に答える
2

Scala の型推論エンジンはNothing、あなたのようなケースで推論することで有名です。簡単に言うと、Scala の型階層には、他のすべての型がその間に存在しなければならない最上位 ( Any) と最下位 ( ) の両方があります。Nothingすべての型には のスーパータイプがあり、すべてAnyNothing型に共通のサブタイプです。

これはあなたにとって何を意味しますか?インスタンスをインスタンス化するときLinkedStackGenericは、型パラメーターの型を省略しますT。これは、型を推論する必要があることを Scala に示します (静的に型付けされた言語であるため、コンパイル時にすべての型を決定する必要があります)。この場合、Scala の型推論エンジンは (ユーザーの期待の観点から) 適切に選択せず、一番下の型 ( Nothing) をパラメーターの型として選択しますT。これで、値「test」を追加しようとすると、Scala コンパイラーは (当然のことながら)を aにString追加できないと文句を言います。LinkedStackGeneric[Nothing]NothingStringsStringNothing

好奇心旺盛な人のために、さらにいくつかのメモ。Nothingは実際には非居住型と呼ばれるものです。つまり、 type のインスタンスが存在することはありませんNothingStringしたがって、すべての s がs であるとは限らないと言いましたが、実際には aがNothingであることは不可能です。StringNothing

于 2013-04-17T20:49:02.590 に答える