这里我有一段scala代码
abstract class Foo[T] {
def unit: T
def add(x:T, y:T): T
}
object Test extends App {
implicit object StringFoo extends Foo[String] {
def add(x:String, y:String): String = x concat y
def unit: String = ""
}
implicit object IntFoo extends Foo[Int] {
def add(x:Int, y:Int):Int = x+y
def unit: Int = 0
}
def sum[T](xs: List[T])(implicit foo: Foo[T]):T =
foo.add(xs.head, sum(xs.tail))
println(sum(List(1,2,3)))
println(sum(List("a","b","c")))
}
成功编译后,我会输入一个" java.util.NoSuchElementException:空列表的头部"
java.util.NoSuchElementException: head of empty list
at scala.collection.immutable.Nil$.head(List.scala:337)
at scala.collection.immutable.Nil$.head(List.scala:334)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$delayedInit$body.apply(test.scala:20)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.App$$anonfun$main$1.apply(App.scala:71)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
at scala.App$class.main(App.scala:71)
at Test$.main(test.scala:5)
at Test.main(test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:71)
at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:139)
at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:71)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:139)
at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:28)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45)
at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:35)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:74)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
但是,如果我以这种方式替换方法sum
,问题就会消失:
def sum[T](xs: List[T])(implicit foo: Foo[T]: T =
if(xs.isEmpty) foo.unit
else foo.add(xs.head, sum(xs.tail))
我确实将sum
应用于非空列表,为什么我会遇到上述问题?
答案 0 :(得分:3)
您感到困惑,因为您使用非空sum
调用方法List
,但堆栈跟踪告诉您列表为空。但是,请仔细查看堆栈和代码。
关键是第一次调用sum
时不会抛出异常,而是第四次调用:
java.util.NoSuchElementException: head of empty list
at scala.collection.immutable.Nil$.head(List.scala:337)
at scala.collection.immutable.Nil$.head(List.scala:334)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$.sum(test.scala:17)
at Test$delayedInit$body.apply(test.scala:20)
您已经编写了一个递归方法,这是一种自我调用的方法 - 但它会一次又一次地调用自己,而不必停下来思考它是否需要继续。不要忘记你的List(1,2,3)
相当于
1 :: 2 :: 3 :: Nil
,因此list.head
将1
,list.tail
将提供2 :: 3 :: Nil
,list.tail.head
将提供2
等等。
在xs
方法中替换sum
参数一次
foo.add(1, sum(List(2,3))
希望您现在可以看到完整的方法调用看起来像
foo.add(1, foo(2, foo(3, foo(Nil.head, sum(Nil.tail)))))
调用Nil.head
应该失败,完全没有你给出的异常,并且添加你指定的保护条件正是修复代码的正确方法。
答案 1 :(得分:0)
因为如果xs为Nil,sum将抛出异常。 你可以从scalaDoc看起来没有 试试这段代码
def sum[T](xs: List[T])(implicit foo: Foo[T]):T =
xs match {
case List() =>
throw new IllegalArgumentException("empty list!")
case List(x) => x
case x :: rest => foo.add(x, sum(rest))
}