了解byref,ref和&

时间:2011-02-17 11:32:51

标签: .net f# reference parameter-passing byref

好吧,我开始明白F#能够管理引用(某些类似C ++的引用)。这使得有可能改变函数中传递的参数值,并使程序员能够返回多个值。 然而,这是我需要知道的:

  1. Ref关键字:关键字ref用于根据值创建对推断类型的值的引用。所以

    let myref = ref 10
    

    这意味着F#将创建一个Ref<int>类型的对象(在可变字段中)放置int 10

    行。所以我假设ref用于创建Ref<'a>类型的实例。这是正确的吗?

  2. 访问值:为了访问存储在引用中的值,我可以这样做:

    let myref = ref 10
    let myval = myref.Value
    let myval2 = !myref
    

    虽然:=运算符只允许我编辑这样的值:

    let myref = ref 10
    myref.Value <- 30
    myref := 40
    

    所以!(Bang)取消引用我的参考。 :=编辑它。我想这也是正确的。

  3. &amp; operator:这个运营商做什么?它是否适用于参考类型?不,我想它必须应用于一个可变值,这会返回什么?参考资料?地址?如果使用互动:

    let mutable mutvar = 10;;
    &a;;
    

    最后一行引发错误,因此我不明白&运算符的用途。

  4. 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是什么?

  5. 调用函数:如何使用函数使用byref参数?

    &运营商参与了,但您能否更好地解释一下?在本文中: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
    

1 个答案:

答案 0 :(得分:28)

参考关键字是的,当您撰写let a = ref 10时,您实际上是在let a = new Ref<int>(10)类型具有可变字段Ref<T>的{​​{1}}。

访问价值 Value:=运算符只是写作的快捷方式:

!

ByRef 是一种特殊类型,可以(合理地)仅在方法参数中使用。这意味着参数本质上应该是指向某个内存位置的指针(在堆或堆栈上分配)。它对应于C#中的a.Value <- 10 // same as writing: a := 10 a.Value // same as writing: !a out修饰符。请注意,您无法创建此类型的本地变量。

&amp; operator 是一种创建值(指针)的方法,该值可以作为参数传递给期望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字段,因为这是一个有用的场景...)。