提问人:LA.27 提问时间:2/12/2022 更新时间:2/12/2022 访问量:305
F# 记录:ref 与可变字段
F# record: ref vs mutable field
问:
在重构我的 F# 代码时,我发现了一条字段类型为 :bool ref
type MyType =
{
Enabled : bool ref
// other, irrelevant fields here
}
我决定尝试将其更改为字段mutable
// Refactored version
type MyType =
{
mutable Enabled : bool
// other fields unchanged
}
此外,我还应用了编译代码所需的所有更改(即更改为 、删除和函数等)。:=
<-
incr
decr
我注意到,在更改之后,一些单元测试开始失败。 由于代码非常大,我真的看不出到底发生了什么变化。
两者的实现是否存在显著差异,可能会改变我的程序的行为?
答:
是的,有区别。引用是一流的值,而可变变量是一种语言结构。
或者,从另一个角度来看,您可能会说单元格是通过引用传递的,而可变变量是通过值传递的。ref
考虑一下:
type T = { mutable x : int }
type U = { y : int ref }
let t = { x = 5 }
let u = { y = ref 5 }
let mutable xx = t.x
xx <- 10
printfn "%d" t.x // Prints 5
let mutable yy = u.y
yy := 10
printfn "%d" !u.y // Prints 10
发生这种情况是因为是一个全新的可变变量,与 无关,因此突变对 没有影响。xx
t.x
xx
x
but 是对与 完全相同的 ref 单元格的引用,因此在引用 via 的同时将新值推送到该单元格中,其效果与通过 引用它具有相同的效果。yy
u.y
yy
u.y
如果你 “复制” a ,则该副本最终指向相同的变量,但如果你复制一个可变变量,则只会复制其值。ref
ref
评论
mutable
你有区别不是因为一个是第一值,通过引用/值或其他东西传递。这是因为 a 本身只是一个容器(类)。ref
当您自己实现时,差异会更加明显。你可以这样做:ref
type Reference<'a> = {
mutable Value: 'a
}
现在看看这两个定义。
type MyTypeA = {
mutable Enabled: bool
}
type MyTypeB = {
Enabled: Reference<bool>
}
MyTypeA
有一个可以直接更改的字段,或者与其他单词是可变的。Enabled
另一方面,你有理论上不可变的,但有一个 Enabled,它引用了一个可变类。MyTypeB
from 只是对一个对象的引用,该对象是可变的,就像 .NET 中的数百万个其他类一样。从上面的类型定义中,您可以创建这样的对象。Enabled
MyTypeB
let t = { MyTypeA.Enabled = true }
let u = { MyTypeB.Enabled = { Value = true }}
创建类型可以更明显地看出,第一个是可变字段,第二个包含具有可变字段的对象。
您可以在 FSharp.Core/prim-types.fs 中找到 的实现,如下所示:ref
[<DebuggerDisplay("{contents}")>]
[<StructuralEquality; StructuralComparison>]
[<CompiledName("FSharpRef`1")>]
type Ref<'T> =
{
[<DebuggerBrowsable(DebuggerBrowsableState.Never)>]
mutable contents: 'T }
member x.Value
with get() = x.contents
and set v = x.contents <- v
and 'T ref = Ref<'T>
F# 中的关键字只是创建此类预定义可变 Reference 对象的内置方法,而不是为此创建自己的类型。它有一些好处,每当您需要在 .NET 中传递 或值时,它都能很好地工作。所以你应该使用 .但你也可以为此使用 a。例如,两个代码示例执行相同的操作。ref
byref
in
out
ref
mutable
有参考
let parsed =
let result = ref 0
match System.Int32.TryParse("1234", result) with
| true -> result.Value
| false -> result.Value
使用可变
let parsed =
let mutable result = 0
match System.Int32.TryParse("1234", &result) with
| true -> result
| false -> result
在这两个示例中,您都会得到一个解析。但是第一个示例将创建一个并将其传递给,而第二个示例将创建一个字段或变量并将其传递给1234
int
FSharpRef
Int32.TryParse
out
Int32.TryParse
上一个:区分联合中的可变内部值
评论