好吧,我开始了解F#能够管理引用(某种类似于引用的C++)。这样就可以更改函数中传递的参数值,还可以使程序员返回多个值。
但是,这是我需要知道的:
ref
用于根据值创建对该推断类型的值的引用。所以let myref = ref 10
这意味着F#将创建一个
Ref<int>
类型的对象,放置在我的int 10
中(在可变字段中)。好。因此,我假设
ref
用于创建Ref<'a>
类型的实例。这是对的吗? let myref = ref 10
let myval = myref.Value
let myval2 = !myref
尽管
:=
运算符只允许我编辑以下值:let myref = ref 10
myref.Value <- 30
myref := 40
因此,
!
(Bang)取消引用了我的引用。然后:=
对其进行编辑。我想这也是正确的。 let mutable mutvar = 10;;
&a;;
最后一行抛出错误,所以我不明白
&
运算符的作用。 byref
怎么样?这对我很重要,但我知道我不明白。我了解它在有关参数传递的函数中使用。当他希望传递的值可以被编辑时使用byref(这有点违背功能语言的原理,但是f#不仅如此)。考虑以下:
let myfunc (x: int byref) =
x <- x + 10
这很奇怪。我知道,如果您有引用
let myref = ref 10
,然后执行此操作以编辑值:myref <- 10
,则会出现错误,因为它应该像这样:myref := 10
。但是,在该函数中我可以使用x
运算符编辑<-
的事实意味着x
不是引用,对吗?如果我假设
x
不是引用,那么我还假设在函数中,当对参数使用byref
时,该参数可以应用可变语法。因此,这只是语法问题,如果我认为这没问题,那么实际上一切正常(没有编译器错误)。但是,x
是什么? 涉及到
&
运算符,但请您更好地解释一下吗?在本文:MSDN Parameters and Arguments中,提供了以下示例:type Incrementor(z) =
member this.Increment(i : int byref) =
i <- i + z
let incrementor = new Incrementor(1)
let mutable x = 10
// A: Not recommended: Does not actually increment the variable. (Me: why?)
incrementor.Increment(ref x)
// Prints 10.
printfn "%d" x
let mutable y = 10
incrementor.Increment(&y) (* Me: & what does it return? *)
// Prints 11.
printfn "%d" y
let refInt = ref 10
incrementor.Increment(refInt) (* Why does it not work in A, but here it does? *)
// Prints 11.
printfn "%d" !refInt
最佳答案
引用关键字是的,当您编写let a = ref 10
时,实际上是在编写let a = new Ref<int>(10)
,而Ref<T>
类型具有可变字段Value
。
访问值 :=
和!
运算符只是编写的快捷方式:
a.Value <- 10 // same as writing: a := 10
a.Value // same as writing: !a
ByRef 是一种特殊类型,只能(合理地)仅在方法参数中使用。这意味着该参数本质上应该是指向某个内存位置(分配在堆或堆栈上)的指针。它对应于C#中的
out
和ref
修饰符。请注意,您不能创建这种类型的局部变量。&运算符是一种创建值(指针)的方法,该值可以作为参数传递给需要
byref
类型的函数/方法。调用函数与
byref
一起使用的示例有效,因为您正在向方法传递对本地可变变量的引用。通过引用,该方法可以更改存储在该变量中的值。以下内容不起作用:
let a = 10 // Note: You don't even need 'mutable' here
bar.Increment(ref a)
原因是您要创建一个
Ref<int>
的新实例,并将a
的值复制到该实例中。然后,Increment
方法修改Ref<int>
实例中存储在堆上的值,但是您不再有对此对象的引用。let a = ref 10
bar.Increment(a)
这是可行的,因为
a
是Ref<int>
类型的值,并且您将指向堆分配的实例的指针传递给Increment
,然后使用!a
从堆分配的引用单元中获取值。(您可以将使用
ref
创建的值用作byref
的参数,因为编译器专门处理这种情况-因为这是一个有用的场景,它将自动引用Value
字段...)。