为什么bigint在一个案例中编译而在另一个案例中不编译?

Sol*_*lma 4 f#

我刚开始使用F#,我发现下面显示的行为令人费解.有什么解释吗?

let bg = bigint 1;;
(* val bg : System.Numerics.BigInteger = 1 *)

let bg = (bigint) 1;;
(* error FS0041: A unique overload for method 'BigInteger' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: System.Numerics.BigInteger(value: byte []) : unit, System.Numerics.BigInteger(value: decimal) : unit, System.Numerics.BigInteger(value: float) : unit, System.Numerics.BigInteger(value: float32) : unit, System.Numerics.BigInteger(value: int) : unit, System.Numerics.BigInteger(value: int64) : unit, System.Numerics.BigInteger(value: uint32) : unit, System.Numerics.BigInteger(value: uint64) : unit *)
Run Code Online (Sandbox Code Playgroud)

Fyo*_*kin 6

那是因为超载.看,bigint实际上是BigInteger类的同义词,并且像函数一样应用它转换为调用构造函数,但是几个构造函数中的哪一个依赖于参数的类型.

当你像函数一样应用它时,这很好用:参数的类型是已知的,编译器可以选择适当的重载.但是,如果您尝试将其视为函数值,则该参数不存在,并且编译器不知道要采用哪个重载.

这是一个更简单的复制品:

type T() =
  member static f (s: string) = s
  member static f (i: int) = I

let a = T.f 1 // works
let b = T.f "abc" // works
let c = T.f // doesn't work: which `f` do you mean?

// possible workaround: create non-overloaded wrappers
let fStr (s: string) = T.f s
let fInt (i: int) = T.f i
let a = fStr // works fine
let b = fInt // works fine, too
Run Code Online (Sandbox Code Playgroud)

结论:重载很糟糕,不要使用它.但如果你坚持使用它,就把它搞定吧.或者使用解决方法.


关于括号的作用

(回应评论)

括号告诉编译器:" 首先,在括号内计算这个表达式,然后取结果并用它做剩下的事 ".所以在括号中放一个东西在语义上等同于给它一个名字,例如:

// Original repro:
let a = (bigint) 5

// Same thing:
let f = bigint
let a = f 5
Run Code Online (Sandbox Code Playgroud)

或者用另一种方式来表达同一个想法:因为括号内不存在函数参数,所以它不能用于计算括号内的表达式; 并且因为没有参数,所以无法解决过载问题.