我正在尝试使用依赖注入为这个单链表实现一个iterable。我期望hasNext返回true而next()返回第一个元素。但它出错了。我在这里做错了什么?
提前感谢您的帮助。
// Definition for singly-linked list from codefights:
class ListNode[T](x : T) {
var value: T = x
var next: Option[ListNode[T]] = None
}
//This class will provide iterator for the above list.
implicit class ln(lns: Option[ListNode[Int]]) extends Iterable[Option[ListNode[Int]]] {
var ptr = lns //temporary variable to store the state of iterator
override def iterator = new Iterator[Option[ListNode[Int]]] {
//if the current node pointed to is None, there are no elements.
override def hasNext = ptr match {case None=> false; case _ => true}
//store the current ptr to temp variable and return it.
override def next = { var tmp = ptr; ptr = ptr.get.next; tmp }
}
//defined +: to perform tests
def +:(that: Option[ListNode[Int]]) = that match {
case None => lns
case _ => that.get.next = lns; that
}
}
//create 3 nodes that will be linked in next step
var a = new ListNode(1)
var b = new ListNode(2)
var c = new ListNode(3)
//link the 3 nodes
val xx : Option[ListNode[Int]]= Some(c) +: Some(b) +: Some(a)
//I know this is not dependency injection. But I wanted to debug the issue.
val ax: ln = new ln(xx)
//ax.size
//checking the iterator manually
ax.iterator.hasNext
ax.iterator.next()
Output:
> defined class ListNode
> defined class ln
> a: ListNode[Int] = ListNode@79c41e43 b: ListNode[Int] =
> ListNode@5fbdb591 c: ListNode[Int] = ListNode@a8e723
>
> xx: Option[ListNode[Int]] = Some(A$A131$A$A131$ListNode@a8e723)
>
> ax: ln = A.A131.A.A131(Some(A$A131$A$A131$ListNode@a8e723),
> Some(A$A131$A$A131$ListNode@5fbdb591),
> Some(A$A131$A$A131$ListNode@79c41e43))
>
> res0: Boolean = false java.util.NoSuchElementException: None.get at
> scala.None$.get(palindrom.sc:345) at
> scala.None$.get(palindrom.sc:343) at
> #worksheet#.ln$$anon$1.next(palindrom.sc:23) at
#worksheet#.ln$$anon$1.next(palindrom.sc:20) at #worksheet#.get$$instance$$res1(palindrom.sc:39) at #worksheet#.#worksheet#(palindrom.sc:84)
更新: 我不允许修改类ListNode。我之前没有提到过。我的错。我刚刚在下面添加了toString用于清晰打印。
但我根据@Dima建议修改了其余的代码。我很惊讶!!因为,我可以像常规列表一样使用地图。非常感谢!!
class ListNode[T](x : T) {
var value: T = x
var next: Option[ListNode[T]] = None
override def toString = x.toString
}
implicit class ln(val lns: ListNode[Int]) extends Iterable[Int] {
override def iterator = Iterator.iterate(Option(lns))(_.flatMap(_.next))
.takeWhile(_.nonEmpty)
.flatten
.map(_.value)
def +:(that: Int) : ListNode[Int] = {
val newNode = new ListNode(that)
newNode.next = Some(lns)
newNode}
}
val xx : ListNode[Int]= 1 +: 2 +: new ListNode(3)
xx.foreach(println)
xx.map( _ +1)
输出
xx:ListNode [Int] = 1
res0:Iterable [Int] = List(2,3,4)
答案 0 :(得分:1)
不要这样做。只是不要。对不起,我开始打字几次试图解释它有什么问题,但我不能......它所有错误。
回到绘图板。
首先,废弃可变状态。你不需要它。现在,只是假装scala中没有var
。
case class ListNode[T](value: T, next: Option[ListNode[T]] = None) {
def +:(head: T) = ListNode(head, Some(this))
}
现在。看起来很奇怪,你的迭代器迭代Option[ListNode[T]]
而不是T
,或者至少是ListNode[T]
。
将其包装到Option
似乎完全没用。
这会迭代T
,因为它似乎最明智,如果您想要ListNode[T]
,请删除最后一个.map
。
如果您坚持使用Option[ListNode[T]]
,请同时删除.map
和.flatten
。
object ListNode {
implicit class Iterable[T](val node: ListNode[T]) extends AnyVal {
def iterator = Iterator
.iterate(Option(node))(_.flatMap(_.next))
.takeWhile(_.nonEmpty)
.flatten
.map(_.value)
}
}
现在您可以执行以下操作:
(1 +: 2 +: ListNode(3))
.iterator
.toList // returns List(1,2,3)
就是这样。如果您要在scala中编写代码,您可能需要花几分钟时间来学习如何使用该语言。你会逐渐欣赏它。