A compreensão byref, ref e &
-
14-11-2019 - |
Pergunta
Bem, eu vim a entender que o F# é capaz de gerenciar referências (algum tipo de C++ como referências).Isso permite que as possibilidades para alterar o valor dos parâmetros passados em funções e também permite que o programador para retornar mais de um valor único.No entanto, aqui está o que eu preciso saber:
Ref palavra-chave:A palavra-chave
ref
é usado para criar, a partir de um valor, uma referência para que o valor do tipo inferido.Então,let myref = ref 10
Isto significa que F# vai criar um objeto do tipo
Ref<int>
colocando ali (no campo mutável) meuint 10
.OK.Então, eu suponho que
ref
é usado para criar instâncias deRef<'a>
escreva.É correto?O acesso de valor:Para acessar o valor armazenado na referência que eu posso fazer isso:
let myref = ref 10 let myval = myref.Value let myval2 = !myref
Enquanto o
:=
operador só me permite editar o valor como este:let myref = ref 10 myref.Value <- 30 myref := 40
Então,
!
(Bang) cancela a minha referência.E:=
editá-lo.Eu suponho que isso é correto também.O operador&:O que faz este operador faz?É para ser aplicado a um tipo de referência?Não, eu acho que deve ser aplicado para um mutável o valor e este devolve o que?A referência?O endereço?Se utilizar interativo:
let mutable mutvar = 10;; &a;;
A última linha lança um erro, então eu não entendo o que o
&
o operador é para.ByRef:O que sobre
byref
?Isso é muito importante para mim, mas eu percebo que eu não entendo isso.Eu entendo que é usada na função sobre a passagem de parâmetro.Usa byref quando ele quer que o valor passado podem ser editados (este é um pouco contra a linguagem funcional' da filosofia, mas f# é algo mais do que isso).Considere o seguinte:let myfunc (x: int byref) = x <- x + 10
Isso é estranho.Eu sei que se você tiver uma referência
let myref = ref 10
e, em seguida, fazer isso para editar o valor:myref <- 10
surge um erro, porque ele deve ser como este:myref := 10
.No entanto, o fato de que, na função que eu possa editarx
usando o<-
operador de meios quex
não é uma referência, né?Se eu assumir que
x
não é uma referência, então eu suponho também que, em exercício de funções, quando utilizarbyref
em um parâmetro, o parâmetro pode ter o mutável sintaxe aplicada.Então é apenas uma questão de sintaxe, se eu assumir isso eu estou OK, e, na verdade, tudo funciona (sem erros de compilador).No entanto, o que éx
?Funções de chamada:Como posso usar uma função utilizando parâmetros byref?
O
&
o operador está envolvido, mas você poderia explicar isso melhor, por favor?Neste artigo: MSDN Parâmetros e Argumentos o exemplo a seguir é fornecido: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
Solução
Ref palavra-chave Sim, quando você escrever let a = ref 10
você está essencialmente escrita let a = new Ref<int>(10)
onde o Ref<T>
tipo tem um campo mutável Value
.
O acesso de valor O :=
e !
os operadores são apenas atalhos para escrever:
a.Value <- 10 // same as writing: a := 10
a.Value // same as writing: !a
ByRef é um tipo especial que pode ser (razoavelmente) usado apenas em parâmetros de método.Isso significa que o argumento deve ser, essencialmente, um ponteiro para algum local de memória (alocado na pilha ou stack).Ele corresponde a out
e ref
modificadores em C#.Observe que você não pode criar variáveis locais deste tipo.
O operador & é uma forma de criar um valor (um ponteiro) que pode ser passado como um argumento para uma função/método esperando um byref
escreva.
Funções de chamada o exemplo com byref
funciona porque você está passando o método de uma referência a um local mutável variável.Através da referência, o método pode alterar o valor armazenado na variável.
A seguir não funciona:
let a = 10 // Note: You don't even need 'mutable' here
bar.Increment(ref a)
A razão é que você está criando uma nova instância de Ref<int>
e você está copiando o valor de a
para este exemplo.O Increment
método, em seguida, modifica o valor armazenado na pilha na instância de Ref<int>
, mas você não tem uma referência a esse objeto.
let a = ref 10
bar.Increment(a)
Isso funciona, porque a
é um valor do tipo Ref<int>
e você está passando um ponteiro para a pilha atribuídos instância para Increment
e, em seguida, obter o valor da pilha atribuídos a referência de célula usando !a
.
(Você pode usar valores criados usando ref
como argumentos para byref
porque o compilador processa este caso especialmente - ele será automaticamente tomar referência do Value
campo porque este é um cenário útil...).