理解byref、ref和 &
-
14-11-2019 - |
题
好吧,我开始明白F#能够管理引用(某种类似于引用的C++)。这使得可以更改函数中传递的参数的值,也使程序员能够返回多个值。然而,这是我需要知道的:
Ref关键字:关键字
ref
用于根据值创建对推断类型的该值的引用。所以let myref = ref 10
这意味着F#将创建一个类型的对象
Ref<int>
把那里(在可变的领域)我的int 10
.好的。所以我想
ref
用于创建Ref<'a>
类型。这是正确的吗?访问值:为了访问存储在引用中的值,我可以这样做:
let myref = ref 10 let myval = myref.Value let myval2 = !myref
而
:=
operator只是让我这样编辑值:let myref = ref 10 myref.Value <- 30 myref := 40
所以
!
(砰)取消引用我的参考。和:=
编辑它。我想这也是正确的。运营商:这个操作员是做什么的?是否要应用于引用类型?不,我想它必须应用于可变值,这返回什么?参考书?地址?如果使用交互式:
let mutable mutvar = 10;; &a;;
最后一行抛出一个错误,所以我不明白
&
运营商是为。ByRef:那呢?
byref
?这对我来说很重要,但我意识到我不明白。我知道它在函数中用于参数传递。当他希望可以编辑传递的值时,可以使用byref(这有点违背函数式语言的哲学,但f#不止于此)。考虑以下几点:let myfunc (x: int byref) = x <- x + 10
这很奇怪。我知道如果你有推荐信的话
let myref = ref 10
然后这样做来编辑值:myref <- 10
它出现错误,因为它应该是这样的:myref := 10
.然而,事实上,在该功能,我可以编辑x
使用<-
运算符的意思是x
不是参考,对吧?如果我认为
x
不是一个参考,那么我也假设,在函数中,当使用byref
在参数上,该参数可以应用可变语法。所以这只是一个语法问题,如果我假设这一点我没问题,而且,事实上,一切都有效(没有编译器错误)。然而,什么是x
?调用函数:如何使用利用byref参数的函数?
该
&
接线员也参与其中,但你能更好地解释一下吗?在本文中: MSDN参数和参数 提供了以下示例: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
解决方案
Ref关键字 是的,当你写 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 是一种特殊类型,可以(合理地)仅在方法参数中使用。这意味着参数本质上应该是指向某些内存位置(在堆或堆栈上分配)的指针。它对应于 out
和 ref
c#中的修饰符。请注意,您不能创建此类型的局部变量。
运营商 是一种创建值(指针)的方法,该值可以作为参数传递给期望 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
字段,因为这是一个有用的场景。..).