Compartilhar via


Células de referência (F#)

Fazer referência a células são locais de armazenamento que permitem criar valores mutáveis, com a semântica de referência.

ref expression

Comentários

Você pode usar o ref operador antes de um valor para criar uma nova célula de referência que encapsula o valor. Em seguida, você pode alterar o valor subjacente, porque ele é mutável.

Uma célula de referência contém um valor real; não é apenas um endereço. Quando você cria uma célula de referência usando o ref operador, você cria uma cópia do valor de base como um valor mutável encapsulado.

Você pode cancelar a referência de uma célula de referência usando o ! (Pronto) operador.

O exemplo de código a seguir ilustra a declaração e o uso de células de referência.

// Declare a reference.
let refVar = ref 6

// Change the value referred to by the reference.
refVar := 50

// Dereference by using the ! operator.
printfn "%d" !refVar

A saída é 50.

Fazer referência a células são instâncias da Ref tipo de registro genérico, que é declarado como segue:

type Ref<'a> =
    { mutable contents: 'a }

O tipo de 'a ref é um sinônimo de Ref<'a>. O compilador e IntelliSense no IDE antigo para este tipo de exibição, mas a definição de base é o último.

O ref operador cria uma nova célula de referência. O código a seguir é a declaração da ref operador.

let ref x = { contents = x }

A tabela a seguir mostra os recursos que estão disponíveis na célula de referência.

Campo, membro ou operador

Descrição

Tipo

Definição

!(operador de cancelamento de referência)

Retorna o valor subjacente.

'a ref -> 'a

let (!) r = r.contents

:=(operador de atribuição)

Altera o valor subjacente.

'a ref -> 'a -> unit

let (:=) r x = r.contents <- x

ref(operador)

Encapsula um valor em uma célula de referência de novo.

'a -> 'a ref

let ref x = { contents = x }

Value(propriedade)

Obtém ou define o valor subjacente.

unit -> 'a

member x.Value = x.contents

contents(campo de registro)

Obtém ou define o valor subjacente.

'a

let ref x = { contents = x }

Há várias maneiras para acessar o valor subjacente. O valor retornado pelo operador de desreferenciamento (!) não é um valor pode ser atribuído. Portanto, se você estiver modificando o valor subjacente, você deve usar o operador de atribuição (:=) em vez disso.

Tanto o Value propriedade e o contents campo são valores pode ser atribuído. Portanto, você pode usá-los para acessar ou alterar o valor subjacente, conforme mostrado no código a seguir.

let xRef : int ref = ref 10

printfn "%d" (xRef.Value)
printfn "%d" (xRef.contents)

xRef.Value <- 11
printfn "%d" (xRef.Value)
xRef.contents <- 12
printfn "%d" (xRef.contents)

A saída é da seguinte maneira.

10
10
11
12

O campo contents é fornecida para compatibilidade com outras versões do ML e gerará um aviso durante a compilação. Para desativar o aviso, use o --mlcompatibility opção de compilador. Para obter mais informações, consulte Opções do compilador (F#).

Exemplo

O código a seguir ilustra o uso de células de referência no parâmetro passando. O Incrementor tipo tem um método Increment que leva um parâmetro que inclui byref no tipo de parâmetro. O byref no parâmetro tipo indica que os chamadores devem passar uma célula de referência ou o endereço de uma variável típico do tipo especificado, neste caso int. O restante do código ilustra como chamar Increment com esses dois tipos de argumentos e mostra o uso da ref o operador em uma variável para criar uma célula de referência (ref myDelta1). Em seguida, ele mostra o uso do operador adress-of (&) para gerar um argumento apropriada. Finalmente, o Increment método for chamado novamente usando uma célula de referência declarada usando um let de vinculação. A linha final do código demonstra o uso do ! o operador a referência da célula de referência para impressão.

type Incrementor(delta) =
    member this.Increment(i : int byref) =
        i <- i + delta

let incrementor = new Incrementor(1)
let mutable myDelta1 = 10
incrementor.Increment(ref myDelta1)
// Prints 10:
printfn "%d" myDelta1  

let mutable myDelta2 = 10
incrementor.Increment(&myDelta2)
// Prints 11:
printfn "%d" myDelta2 

let refInt = ref 10
incrementor.Increment(refInt)
// Prints 11:
printfn "%d" !refInt

Para obter mais informações sobre como passar por referência, consulte Parâmetros e argumentos (F#).

ObservaçãoObservação

C# os programadores devem saber que ref funciona de forma diferente no F# que no C#. Por exemplo, o uso de ref Quando você passar um argumento não tem o mesmo efeito em F# como acontece em C#.

Fazer referência a células vs.Variáveis mutáveis

Referência a células e mutáveis variáveis geralmente podem ser usadas nas mesmas situações. No entanto, há algumas situações nas quais variáveis mutáveis não podem ser usadas e você deve usar uma célula de referência em vez disso. Em geral, você deve preferir mutáveis variáveis, onde são aceitas pelo compilador. No entanto, em expressões que geram os fechamentos, o compilador irá relatar que você não pode usar variáveis mutáveis. Fechamentos de são funções locais que são geradas por determinados F# expressões, como, por exemplo, as expressões lambda, expressões de seqüência, expressões de computação, e funções de curried que usam parcialmente aplicada argumentos. Os fechamentos gerados por essas expressões são armazenados para avaliação posterior. Esse processo não é compatível com variáveis mutáveis. Portanto, se você precisar de um estado mutável em uma expressão como essa, é necessário que usar células de referência. Para obter mais informações sobre feriados, consulte fechamentos (F#).

O exemplo de código a seguir demonstra o cenário no qual você deve usar uma célula de referência.

// Print all the lines read in from the console.
let PrintLines1() =
    let mutable finished = false
    while not finished do
        match System.Console.ReadLine() with
        | null -> finished <- true
        | s -> printfn "line is: %s" s


// Attempt to wrap the printing loop into a 
// sequence expression to delay the computation.
let PrintLines2() =
    seq {
        let mutable finished = false
        // Compiler error:
        while not finished do  
            match System.Console.ReadLine() with
            | null -> finished <- true
            | s -> yield s
    }

// You must use a reference cell instead.
let PrintLines3() =
    seq {
        let finished = ref false
        while not !finished do
            match System.Console.ReadLine() with
            | null -> finished := true
            | s -> yield s
    }

No código anterior, a célula de referência finished está incluído no estado local, ou seja, variáveis de feriado são criadas em usado inteiramente dentro da expressão, neste caso uma expressão de seqüência., Considere o que ocorre quando as variáveis são não-local. Fechamentos também podem acessar o estado de não-local, mas quando isso ocorre, as variáveis são copiadas e armazenadas pelo valor. Esse processo é conhecido como a semântica de valor. Isso significa que os valores no momento da cópia são armazenados e quaisquer alterações subseqüentes às variáveis não são refletidas. Se você desejar controlar as alterações das variáveis de não-local ou, em outras palavras, se você precisar de um fechamento que interage com o estado de não-local usando a semântica de referência, você deve usar uma célula de referência.

Os exemplos de código a seguir demonstram o uso de células de referência em feriados. Nesse caso, o fechamento resulta da aplicação parcial dos argumentos da função.

// The following code demonstrates the use of reference
// cells to enable partially applied arguments to be changed
// by later code.

let increment1 delta number = number + delta

let mutable myMutableIncrement = 10

// Closures created by partial application and literals.
let incrementBy1 = increment1 1
let incrementBy2 = increment1 2

// Partial application of one argument from a mutable variable.
let incrementMutable = increment1 myMutableIncrement

myMutableIncrement <- 12

// This line prints 110.
printfn "%d" (incrementMutable 100)

let myRefIncrement = ref 10

// Partial application of one argument, dereferenced
// from a reference cell.
let incrementRef = increment1 !myRefIncrement

myRefIncrement := 12

// This line also prints 110.
printfn "%d" (incrementRef 100)

// Reset the value of the reference cell.
myRefIncrement := 10

// New increment function takes a reference cell.
let increment2 delta number = number + !delta

// Partial application of one argument, passing a reference cell
// without dereferencing first.
let incrementRef2 = increment2 myRefIncrement

myRefIncrement := 12

// This line prints 112.
printfn "%d" (incrementRef2 100)

Consulte também

Referência

Símbolo e o referência de operador (F#)

Conceitos

Parâmetros e argumentos (F#)

Outros recursos

Referência de linguagem do F#