Подтвердить что ты не робот

Понимание byref, ref и &

Ну, я понял, что F # умеет управлять ссылками (как-то вроде ссылок на С++). Это позволяет изменять значение параметров, передаваемых в функции, а также позволяет программисту возвращать более одного значения. Однако вот что мне нужно знать:

  • Ссылка на ключевое слово: Ключевое слово ref используется для создания из значения ссылки на это значение выводимого типа. Так

    let myref = ref 10
    

    Это означает, что F # создаст объект типа Ref<int>, поместив туда (в изменяемое поле) my int 10.

    OK. Поэтому я предполагаю, что ref используется для создания экземпляров типа Ref<'a>. Правильно ли это?

  • Значение доступа: для доступа к значению, хранящемуся в ссылке, я могу сделать это:

    let myref = ref 10
    let myval = myref.Value
    let myval2 = !myref
    

    В то время как оператор := позволяет мне изменить значение, подобное этому:

    let myref = ref 10
    myref.Value <- 30
    myref := 40
    

    Итак ! (Bang) разыгрывает мою ссылку. И := отредактируйте его. Я полагаю, это тоже правильно.

  • Оператор и оператор: что делает этот оператор? Должен ли он применяться к эталонному типу? Нет, я думаю, это должно быть применено к изменяемому значению, и это возвращает что? Ссылка? Адрес? Если вы используете интерактивный интерфейс:

    let mutable mutvar = 10;;
    &a;;
    

    Последняя строка вызывает ошибку, поэтому я не понимаю, для чего предназначен оператор &.

  • ByRef: Как насчет byref? Это очень важно для меня, но я понимаю, что не понимаю. Я понимаю, что он используется в функции для передачи параметров. Один использует byref, когда хочет, чтобы переданное значение можно было отредактировать (это немного противоречит философии функциональных языков, но f # - это нечто большее). Рассмотрим следующее:

    let myfunc (x: int byref) =
        x <- x + 10
    

    Это странно. Я знаю, что если у вас есть ссылка let myref = ref 10, а затем сделайте это, чтобы изменить значение: myref <- 10 возникает ошибка, потому что она должна быть такой: myref := 10. Однако тот факт, что в этой функции я могу редактировать x с помощью оператора <-, означает, что x не является ссылкой, правильно?

    Если я предполагаю, что x не является ссылкой, я также предполагаю, что в функциях при использовании параметра byref для параметра этот параметр может иметь применяемый mutable синтаксис. Так что это всего лишь вопрос синтаксиса, если я предполагаю, что это нормально, и на самом деле все работает (ошибок компилятора нет). Однако что такое 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
    
4b9b3361

Ответ 1

ключевое слово Ref Да, когда вы пишете 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

ByRef - это особый тип, который может (разумно) использоваться только в параметрах метода. Это означает, что аргумент должен быть по существу указателем на некоторую ячейку памяти (выделенную в куче или стеке). Он соответствует модификаторам out и ref в С#. Обратите внимание: вы не можете создать локальную переменную этого типа.

Оператор и - это способ создания значения (указателя), которое может быть передано как аргумент функции/методу, ожидающему тип 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, потому что это полезный сценарий...).