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çã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#)