在关于Fibonacci数字创建的Stackoverflow帖子中,我找到了方法#::
(What is the fastest way to write Fibonacci function in Scala?)。在ScalaDocs中,我发现此条目(请参阅此处1)将哈希冒号冒号方法描述为允许使用#::。
我意识到我可以像这样使用斐波那契函数
def fibonacci: Stream[Long] = {
def tail(h: Long, n: Long): Stream[Long] = h #:: tail(n, h + n)
tail(0, 1)
}
fibonacci(10) //res4: Long = 55
我应该如何理解ScalaDocs的解释?你能举个例子吗?
为什么没有必要在上面的fibonacci
函数中定义参数?
答案 0 :(得分:4)
在您的示例h #:: tail(n, h + n)
中创建一个新流,其中h
是流的头部,tail(n, h + n)
是一个将被懒惰评估的流。
另一个(也许更容易)的例子是将自然数定义为BigInt流。
def naturalNumbers = {
def next(n: BigInt) : Stream[BigInt] = n #:: next(n + 1)
next(0)
}
println(naturalNumbers)
会导致打印Stream(0, ?)
,因为头部是严格的,这意味着它将始终被评估。尾部为next(1)
,仅在需要时进行评估。
在您的示例中,fibonacci(10)
是fibonacci.apply(10)
的语法糖,它在Stream
类中定义,并在流中生成带索引的元素。
您还可以使用流做很多其他事情。例如,获取大于100的第一个斐波纳契数:fibonacci.dropWhile(_ <= 100).head
或者只打印前100个斐波纳契数println(fibonacci.take(100).toList)
答案 1 :(得分:4)
方法#::
是为Streams定义的。它类似于列表的::
方法。 List和Stream之间的主要区别在于Stream的元素是惰性求值的。
在最后一行发生了一些scala魔法。实际上,首先您要评估fibonacci
表达式,然后返回Stream
个对象。此流的第一个和第二个元素是0和1,如下所示,从示例的第三行开始,Stream的其余部分通过递归调用定义。然后你从流中提取第十个元素,它的计算结果为55。
在下面的代码中,我显示了对第四个List元素
的类似访问权限val list = List(1,2,3,4,5)
println(list(3)) // prints 4
简而言之,将Streams视为无限列表。您可以在此处找到有关Streams的更多信息http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream
答案 2 :(得分:3)
对#2的快速回答是fibonacci(10)
不是带参数的函数调用,它是一个没有参数的函数调用,后跟调用参数“10”返回的任何内容。
如果这样写的话会更容易理解:
scala> val s = fibonacci
s: Stream[Long] = Stream(0, ?)
scala> s(10)
res1: Long = 55