2011-02-17 24 views
22

Bueno, llegué a entender que F # es capaz de gestionar referencias (algún tipo de C++ como referencias). Esto permite las posibilidades de cambiar el valor de los parámetros pasados ​​en funciones y también permite que el programador devuelva más de un valor individual. Sin embargo esto es lo que necesito saber:Comprensión de byref, ref y &

  1. Ref palabra clave: La palabra clave ref se utiliza para crear, a partir de un valor, una referencia a ese valor del tipo inferido. Así

    let myref = ref 10 
    

    Esto significa que F # creará un objeto de tipo Ref<int> poner allí (en el campo mutable) mi int 10.

    OK. Así que supongo que ref se usa para crear instancias del tipo Ref<'a>. ¿Es correcto? valor

  2. acceso: Para acceder a un valor almacenado en referencia Puedo hacer esto:

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

    Mientras que el operador := simplemente me permite editar el valor de la siguiente manera:

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

    Así ! (Bang) desreferencias mi referencia. Y := editarlo. Supongo que esto también es correcto.

  3. El operador &: ¿Qué hace este operador? ¿Se aplicará a un tipo de referencia? No, supongo que debe aplicarse a un valor mutable y esto devuelve qué? ¿La referencia? ¿La dirección? Si se utiliza interactivo:

    let mutable mutvar = 10;; 
    &a;; 
    

    La última línea genera un error por lo que no entiendo lo que el operador es para &.

  4. ByRef: ¿Qué hay de byref? Eso es muy importante para mí, pero me doy cuenta de que no lo entiendo. Entiendo que se usa en función del paso de parámetros. Uno usa byref cuando quiere que el valor pasado pueda ser editado (esto es un poco contrario a la filosofía de los lenguajes funcionales, pero f # es algo más que eso). Considere lo siguiente:

    let myfunc (x: int byref) = 
        x <- x + 10 
    

    Esto es extraño. Sé que si tiene una referencia let myref = ref 10 y luego hace esto para editar el valor: myref <- 10, se produce un error porque debería ser así: myref := 10. Sin embargo, el hecho de que en esa función puedo editar x utilizando el operador <- significa que x no es una referencia, ¿verdad?

    Supongo que x no es una referencia, entonces supongo también que, en las funciones, al usar byref en un parámetro, ese parámetro puede tener aplicada la sintaxis mutable. Entonces es solo una cuestión de sintaxis, si asumo que estoy bien, y, de hecho, todo funciona (no hay errores de compilación). Sin embargo, ¿qué es x?

  5. Funciones de llamada: ¿Cómo puedo utilizar una función que utiliza parámetros byref?

    El operador & está involucrado, pero ¿podría explicar esto mejor por favor? En este artículo: MSDN Parameters and Arguments se proporciona el siguiente ejemplo:

    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 
    
+8

Sugerencias de estilo: los interrogantes múltiples no hacen que sus preguntas sean más "cuestionables" y le hacen parecer un poco tonto: una es suficiente. El texto en mayúsculas es difícil de leer y generalmente se entiende que significa que está gritando: use [formateo] (http://stackoverflow.com/editing-help) (como cursiva y negrita) para enfatizar. –

Respuesta

25

Ref palabra clave Sí, cuando se escribe let a = ref 10 básicamente estás escribiendo let a = new Ref<int>(10) donde el tipo Ref<T> tiene un campo mutable Value.

valor Acceso Los := y ! operadores son sólo atajos para escribir:

a.Value <- 10 // same as writing: a := 10 
a.Value  // same as writing: !a 

ByRef es un tipo especial que se puede (razonablemente) que se utiliza sólo en los parámetros del método. Significa que el argumento debería ser esencialmente un puntero a alguna ubicación de memoria (asignada en montón o pila). Corresponde a los modificadores out y ref en C#. Tenga en cuenta que no puede crear una variable local de este tipo.

& El operador es una manera de crear un valor (un puntero) que se puede pasar como argumento a una función/método esperando un tipo byref.

Llamando a las funciones el ejemplo con byref funciona porque está pasando el método una referencia a una variable mutable local. A través de la referencia, el método puede cambiar el valor almacenado en esa variable.

El siguiente no funciona:

let a = 10   // Note: You don't even need 'mutable' here 
bar.Increment(ref a) 

La razón es que va a crear una nueva instancia de Ref<int> y que está copiando el valor de a en este caso. El método Increment luego modifica el valor almacenado en el montón en la instancia de Ref<int>, pero ya no se hace referencia a este objeto.

let a = ref 10 
bar.Increment(a) 

esto funciona, porque a es un valor de tipo Ref<int> y estás pasando un puntero a la instancia montón asignados a Increment y luego obtener el valor de la celda de referencia montón asignados utilizando !a.

(puede usar valores creados usando ref como argumentos para byref porque el compilador maneja este caso especialmente - tomará automáticamente la referencia del campo Value porque este es un escenario útil ...).

+0

Muchas gracias Tomas :) – Andry

+0

Hoever lo siento Tomas, pero cuando se pasa una referencia a una función que acepta un byref, el intérprete se vuelve loco ... – Andry

+0

@Andry: "loco" en qué sentido? Comportamiento que no esperaba o algún mensaje de error? (Estaré feliz de aclarar esa parte ...) –