Понимание byref, ref и & - PullRequest
       104

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

23 голосов
/ 17 февраля 2011

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

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

    let myref = ref 10
    

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

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

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

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

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

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

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

  3. Оператор &: что делает этот оператор? Это должно быть применено к ссылочному типу? Нет, я думаю, это должно быть применено к изменяемому значению, и это возвращает что? Ссылка? Адрес? При использовании интерактивного:

    let mutable mutvar = 10;;
    &a;;
    

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

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

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

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

    Если я предполагаю, что x не является ссылкой, то я также предполагаю, что в функциях при использовании byref для параметра к этому параметру может применяться изменяемый синтаксис. Так что это просто вопрос синтаксиса, если я предполагаю, что все в порядке, и, на самом деле, все работает (без ошибок компилятора). Однако что такое x?

  5. Вызов функций: как я могу использовать функцию, использующую параметры 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
    

1 Ответ

28 голосов
/ 17 февраля 2011

Ключевое слово 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 в 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, потому что это полезный сценарий ...).

...