Scala中的中缀构造函数无法解析?

时间:2015-09-28 15:03:12

标签: scala constructor infix-notation

楼梯书中的一个例子:

package ky.example

object Example {
  abstract class MyList[+T] {
    def isEmpty: Boolean
    def head: T
    def tail: MyList[T]

    def length: Int = if(isEmpty) 0 else 1 + tail.length
    def drop(n: Int): MyList[T] = {
      if(isEmpty) MyNil
      else tail.drop(n - 1)
    }
    def map[U](func: T => U): MyList[U] = {
      if(isEmpty) MyNil
//      else new ::(func(head), tail.map(func))
      else func(head) :: tail.map(func) // cannot resolve symbol ::
    }
  }

  case object MyNil extends MyList[Nothing] {
    override def isEmpty: Boolean = true

    override def tail: MyList[Nothing] = throw new NoSuchElementException("tail of MyNil")

    override def head: Nothing = throw new NoSuchElementException("head of MyNil")
  }

  final case class ::[T](val head: T, val tail: MyList[T]) extends MyList[T] {
    override def isEmpty: Boolean = false
  }
  object :: {
    def apply[T](h: T, t: MyList[T]) = {
      new ::(h, t)
    }
  }

}

编译器说它无法解析符号::。如果我使用前缀版本而不是中缀版本(该行被注释掉),则没有错误。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

中缀表示法不适用于伴随对象的apply方法。要使用中缀表示法,您必须在::类中为MyList提供方法定义。如果添加到MyList

,以下代码可以解决问题
def ::[U >: T](h: U): MyList[U] = {
  new ::(h, this)
}

MyList的结果定义如下:

abstract class MyList[+T] {
  def isEmpty: Boolean
  def head: T
  def tail: MyList[T]

  def length: Int = if(isEmpty) 0 else 1 + tail.length
  def drop(n: Int): MyList[T] = {
    if(isEmpty) MyNil
    else tail.drop(n - 1)
  }
  def map[U](func: T => U): MyList[U] = {
    if(isEmpty) MyNil
    else func(head) :: tail.map(func)
  }

  def ::[U >: T](h: U): MyList[U] = {
    new ::(h, this)
  }
}

case object MyNil extends MyList[Nothing] {
  override def isEmpty: Boolean = true

  override def tail: MyList[Nothing] = throw new NoSuchElementException("tail of MyNil")

  override def head: Nothing = throw new NoSuchElementException("head of MyNil")
}

final case class ::[T](val head: T, val tail: MyList[T]) extends MyList[T] {
  override def isEmpty: Boolean = false
}