tl;博士:
fibs 被定义为Stream[BigInt],因此当您在其前面添加Int (1 #:: ...) 时,编译器会查找从Int 到BigInt 的隐式转换并在@ 中找到它987654327@
这里发生了几件事。
1) BigInt 伴随对象定义了从Int 到BigInt 的隐式转换:
implicit def int2bigInt(i: Int): BigInt = apply(i)
这意味着无论您需要BigInt,您都可以提供Int,隐式转换将转换该值。你也可以说Ints 可以被视为BigInts。
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,但是,正如我之前提到的,Ints 可以被视为 BigInts,因此它们会自动转换为 BigInts 并且所有内容都会编译。
当你这样做时:val s1:Stream[BigInt] = 1 #:: 2 #:: Stream.empty
您正在做不同的事情:您在右侧创建 Stream[Int] (Stream.empty 类型被推断为 Int 从您传递的 1,2 值),然后您将此值分配给 @987654352 @瓦尔。
不幸的是,没有从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
Lists 还存在其他问题:与 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 推断为Any,因为Any 是最严格的超类型BigInt 也是 Int 的超类型。
由于这使编译器满意,因此不寻找隐式转换,结果列表是一个 List[Any],您不能再将其用作整数列表。
您基本上可以调用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
我不是 100% 确定这一点(如果我错了,请任何人纠正我):