我应该如何在Scala中使用#:: / hash冒号?

时间:2014-01-12 15:41:46

标签: scala pattern-matching scala-collections

在关于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函数中定义参数?

3 个答案:

答案 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