有时错误 FS0037,非常混乱
Error FS0037 sometimes, very confusing
如果我编写以下 F# 代码,编译器会发出错误。
let a = 123
let a = 123
产生的错误是:
error FS0037: Duplicate definition of value 'a'
如果我在这样的函数中编写相同的代码:
let fctn =
let a =123
let a =123
a
它不会产生任何错误。
我不明白其中的区别。谁能解释一下?
编辑:我在模块级别编写的第一个代码。
第一个定义了两个同名的 public 值。
第二个隐藏(阴影)值。
第一个你会有外部可见的状态变化(a
表现得像可变的)而第二个你不能(你有两个 a
在不同的范围)。
如果您使用 #light off
ML 语法编写语句,它会立即变得显而易见。
关于范围和阴影
如 CaringDev 所述(但未解释),当您使范围更明显时(使用 let ... in ...
构造 #light
,您可能会看到阴影是什么让你缩短一点-但即使没有#light off
)
你仍然可以使用它
试试这个:
> let a = 233 in let a = 555 in a;;
val it : int = 555
如您所见,表达式的计算结果为 a
的 shadowed 值 - 但原始值并未丢失:
> let a = 233 in (let a = 555 in a), a;;
val it : int * int = (555, 233)
它只是不在内部 let ... in ...
的范围内
顺便说一句:您可以将示例重写为:
let fctn =
let a = 123 in
(let a =123 in a)
(我添加括号只是为了使这一点更明显)
模块级别的另一个真正定义了模块范围的值,并不是真正的表达式而是定义
我同意这令人困惑。问题是 let
用作局部变量(在函数内)和用作全局定义(在模块内)时的行为不同。
全局定义(在模块中)被编译为静态class的静态成员,因此名称只能使用一次。这意味着顶级使用:
let a = 10
let a = 11
... 是一个错误,因为 F# 必须生成两个同名的静态成员。
局部定义(在函数或其他嵌套范围内)被编译为 IL,变量名基本上消失了(IL 使用堆栈代替)。在这种情况下,F# 允许变量隐藏,您可以隐藏现有名称的变量。这可以在函数内部,甚至可以只是一个 do
块:
do
let a = 10
let a = 11
()
这有点令人困惑,因为变量阴影仅适用于本地范围,但不适用于顶层。当你知道事情是如何编译的时候,这是有道理的..
如果我编写以下 F# 代码,编译器会发出错误。
let a = 123
let a = 123
产生的错误是:
error FS0037: Duplicate definition of value 'a'
如果我在这样的函数中编写相同的代码:
let fctn =
let a =123
let a =123
a
它不会产生任何错误。
我不明白其中的区别。谁能解释一下?
编辑:我在模块级别编写的第一个代码。
第一个定义了两个同名的 public 值。
第二个隐藏(阴影)值。
第一个你会有外部可见的状态变化(a
表现得像可变的)而第二个你不能(你有两个 a
在不同的范围)。
如果您使用 #light off
ML 语法编写语句,它会立即变得显而易见。
关于范围和阴影
如 CaringDev 所述(但未解释),当您使范围更明显时(使用 let ... in ...
构造 #light
,您可能会看到阴影是什么让你缩短一点-但即使没有#light off
)
试试这个:
> let a = 233 in let a = 555 in a;;
val it : int = 555
如您所见,表达式的计算结果为 a
的 shadowed 值 - 但原始值并未丢失:
> let a = 233 in (let a = 555 in a), a;;
val it : int * int = (555, 233)
它只是不在内部 let ... in ...
顺便说一句:您可以将示例重写为:
let fctn =
let a = 123 in
(let a =123 in a)
(我添加括号只是为了使这一点更明显)
模块级别的另一个真正定义了模块范围的值,并不是真正的表达式而是定义
我同意这令人困惑。问题是 let
用作局部变量(在函数内)和用作全局定义(在模块内)时的行为不同。
全局定义(在模块中)被编译为静态class的静态成员,因此名称只能使用一次。这意味着顶级使用:
let a = 10
let a = 11
... 是一个错误,因为 F# 必须生成两个同名的静态成员。
局部定义(在函数或其他嵌套范围内)被编译为 IL,变量名基本上消失了(IL 使用堆栈代替)。在这种情况下,F# 允许变量隐藏,您可以隐藏现有名称的变量。这可以在函数内部,甚至可以只是一个 do
块:
do
let a = 10
let a = 11
()
这有点令人困惑,因为变量阴影仅适用于本地范围,但不适用于顶层。当你知道事情是如何编译的时候,这是有道理的..