Fazer referência a células (F#)

Fazer referência a células são locais de armazenamento que permitem criar valores mutáveis com 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 ! (bang) 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 de genéricos, que é declarado da seguinte maneira.

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

O tipo de 'a ref é um sinônimo de Ref<'a>.O compilador e IntelliSense no IDE exibem o antigo para este tipo, mas a definição subjacente é 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 nova célula de referência.

'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 que pode ser atribuído.Portanto, se você estiver modificando o valor de base, 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ídos.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 na passagem por parâmetro.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 operador em uma variável para criar uma célula de referência (ref myDelta1).Ele mostra o uso do operador adress-of (&) para gerar um argumento apropriada.Finalmente, o Increment método for chamado novamente por meio de uma célula de referência que é declarada usando um let vinculação.A linha final do código demonstra o uso da ! 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ê passa um argumento não tem o mesmo efeito no 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, existem 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 variáveis mutáveis onde eles são aceitas pelo compilador.No entanto, em expressões que geram 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 certos F# expressões, como, por exemplo, as expressões lambda, expressões de seqüência, expressões de computação, e funções 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 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 em que 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, as variáveis que estão no fechamento 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#