我想知道下面的Stream类型是如何投放的?
type NTy = BigInt
def streamFib(n: Int): NTy = {
lazy val fibs: Stream[NTy] = 1 #:: 1 #:: fibs.zip(fibs.tail).map(n => n._1 + n._2)
fibs.drop(n - 1).head
}
此编译并streamFib
返回BigInt
类型(如预期的那样?)。
我还注意到了一些行为:
val s1:Stream[BigInt] = 1 #:: 2 #:: Stream.empty // incorrect, found Int required BigInt
val s2:Stream[BigInt] = 1 #:: 2 #:: Stream.empty[BigInt] // correct
val l1:List[BigInt] = 1 :: 2 :: List.empty[BigInt] // incorrect, found Any required BigInt
val l2:List[BigInt] = 1 :: BigInt(2) :: List.empty[BigInt] // correct
答案 0 :(得分:3)
fibs
被定义为Stream[BigInt]
,因此当您向Int
添加1 #:: ...
时,编译器将从Int
查找隐式转换} BigInt
并在BigInt.int2bigInt
这里有几件事情。
1)BigInt
随播广告对象定义了从Int
到BigInt
的隐式转化:
implicit def int2bigInt(i: Int): BigInt = apply(i)
这意味着,只要您需要BigInt
,就可以提供Int
,隐式转化将转换该值。您还可以说Int
可以被视为 BigInt
。
2)以冒号结尾的方法是右关联。这意味着1 #:: 2 #:: Stream.empty[BigInt]
可以有效地重写为Stream.empty[BigInt].#::(2).#::(1)
现在,如果您查看Stream.#::
(def #::(hd: A): Stream[A]
)的签名,您会看到Stream[BigInt].#::(x)
只有在x
为BigInt
时才能进行编译
当您致电1 #:: 2 #:: Stream.empty[BigInt]
时,您呼叫Stream[BigInt].#::
传递Int
值而不是BigInt
,但正如我之前提到的,Int
可以被视为 BigInt
,因此它们会自动转换为BigInts并且所有内容都会编译。
执行此操作时:val s1:Stream[BigInt] = 1 #:: 2 #:: Stream.empty
你正在做一个不同的事情:你正在右边创建一个Stream[Int]
(Stream.empty
类型从你传递的1,2值推断为Int)然后你分配这个值到Stream[BigInt]
val。
不幸的是,即使Stream[A]
可以被视为 Stream[B]
,也没有从A
到B
的隐式转换,因此编译失败
您可以通过以下方式定义自己的隐式转换:
implicit def asBigIntStream(xs: Stream[Int]): Stream[BigInt] = xs.map(BigInt.int2bigInt)
val s1:Stream[BigInt] = 1 #:: 2 #:: Stream.empty //This now works
List
s还有其他问题:与Stream
不同,List
缺点定义为:
def ::[B >: A] (x: B): List[B]
使用Stream.#::(x)
,您需要x与您预先x
前面的Stream完全相同。对于List.::(x)
,x
(类型为B
)可以是列表类型的超类型的实例。结果列表将是List[B]
,即在列表前面可以扩展其类型。
因此,当您执行2 :: List.empty[BigInt]
时,您有效地呼叫List[A].::(x: B)
,其中A
为BigInt
,而B
被推断为{{ 1}}因为Any
是Any
最严格的超类型,也是BigInt
的超类型。
由于这使编译器满意,因此不会查找隐式转换,结果列表是List [Any],您不能再将其用作整数列表。
您基本上可以致电Int
获取whatever :: List[X]
,其中List[Y]
是Y
的最严格超类型和X
的类型
那么,whatever
为什么val l1:List[BigInt] = 1 :: 2 :: List.empty[BigInt]
没有工作呢?
这是因为类型推断。让我们重写两个删除右关联性的表达式:
val l2 : List[BigInt] = 1 :: BigInt(2) :: List.empty[BigInt]
我不是百分百肯定的(如果我错了,请任何人纠正我):
编译器只能在val l1: List[BigInt] = (List.empty[BigInt].::(2)).::(1) // incorrect, found Any required BigInt
val l2: List[BigInt] = (List.empty[BigInt].::(BigInt(2))).::(1) // correct
的最后一个应用程序上帮助进行类型推断
在应用::
之前,(List.empty[BigInt].::(2))
已经List[Any]
,所以我们无能为力
.::(1)
已经是(List.empty[BigInt].::(BigInt(2)))
,编译器可以尝试将List[BigInt]
设为.::(1)
(从而寻找隐式转换)