Понимание byref, ref и &
-
14-11-2019 - |
Вопрос
Что ж, я понял, что F # может управлять ссылками (что-то вроде ссылок, подобных C ++).Это дает возможность изменять значения параметров, передаваемых в функции, а также позволяет программисту возвращать более одного значения.Однако вот что мне нужно знать:
Ключевое слово ссылки:Ключевое слово
ref
используется для создания из значения ссылки на это значение выведенного типа.Такlet myref = ref 10
Это означает, что F# создаст объект типа
Ref<int>
помещая туда (в изменяемое поле) мойint 10
.ХОРОШО.Поэтому я предполагаю, что
ref
используется для создания экземпляровRef<'a>
тип.Это правильно?Значение доступа:Чтобы получить доступ к значению, хранящемуся в ссылке, я могу сделать это:
let myref = ref 10 let myval = myref.Value let myval2 = !myref
В то время
:=
оператор просто позволяет мне редактировать значение следующим образом:let myref = ref 10 myref.Value <- 30 myref := 40
Так
!
(Бах) разыменовывает мою ссылку.И:=
отредактируйте его.Полагаю, это тоже правильно.Оператор:Что делает этот оператор?Следует ли применять его к ссылочному типу?Нет, я думаю, это должно быть применено к изменяемому значению, и что это возвращает?Ссылка?Адрес?При использовании интерактивного:
let mutable mutvar = 10;; &a;;
Последняя строка выдает ошибку, поэтому я не понимаю, что
&
оператор предназначен для.Автор ссылки:Как насчет
byref
?Для меня это очень важно, но я понимаю, что не понимаю этого.Я понимаю, что он используется в функции передачи параметров.Кто-то использует byref, когда хочет, чтобы переданное значение можно было редактировать (это немного противоречит философии функциональных языков, но f# - это нечто большее).Учтите следующее:let myfunc (x: int byref) = x <- x + 10
Это странно.Я знаю, что если у вас есть ссылка
let myref = ref 10
а затем сделайте это, чтобы отредактировать значение:myref <- 10
возникает ошибка, потому что должно быть так:myref := 10
.Однако тот факт, что в этой функции я могу редактироватьx
используя<-
оператор означает, чтоx
это не отсылка, да?Если я предположу, что
x
не является ссылкой, то я также предполагаю, что в функциях при использованииbyref
к параметру, к этому параметру может быть применен изменяемый синтаксис.Так что это всего лишь вопрос синтаксиса, если я так предполагаю, то со мной все в порядке, и на самом деле все работает (без ошибок компилятора).Однако что такоеx
?Вызов функций:Как я могу использовать функцию, использующую параметры byref?
А
&
В этом участвует оператор, но не могли бы вы объяснить это получше, пожалуйста?В этой статье: Параметры и аргументы MSDN приведен следующий пример: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
Решение
Ключевое слово ссылки Да, когда ты пишешь let a = ref 10
ты по сути пишешь let a = new Ref<int>(10)
где Ref<T>
тип имеет изменяемое поле Value
.
Значение доступа А :=
и !
операторы — это просто ярлыки для записи:
a.Value <- 10 // same as writing: a := 10
a.Value // same as writing: !a
По ссылке — это специальный тип, который можно (разумно) использовать только в параметрах метода.Это означает, что аргумент должен быть по существу указателем на некоторую область памяти (выделенную в куче или стеке).Это соответствует out
и ref
модификаторы в C#.Обратите внимание, что вы не можете создать локальную переменную этого типа.
Оператор это способ создать значение (указатель), которое можно передать в качестве аргумента функции/методу, ожидающему byref
тип.
Вызов функций пример с byref
работает, потому что вы передаете методу ссылку на локальную изменяемую переменную.По ссылке метод может изменить значение, хранящееся в этой переменной.
Следующее не работает:
let a = 10 // Note: You don't even need 'mutable' here
bar.Increment(ref a)
Причина в том, что вы создаете новый экземпляр Ref<int>
и вы копируете значение a
в этот экземпляр.А Increment
затем метод изменяет значение, хранящееся в куче в экземпляре Ref<int>
, но у вас больше нет ссылки на этот объект.
let a = ref 10
bar.Increment(a)
Это работает, потому что a
это значение типа Ref<int>
и вы передаете указатель на экземпляр, выделенный в куче, Increment
а затем получить значение из эталонной ячейки, выделенной в куче, используя !a
.
(Вы можете использовать значения, созданные с помощью ref
в качестве аргументов в пользу byref
поскольку компилятор обрабатывает этот случай особым образом — он автоматически возьмет ссылку на Value
поле, потому что это полезный сценарий...).