Не удается обновить изменяемое поле в структуре? - PullRequest
0 голосов
/ 08 ноября 2018

Может кто-нибудь сказать мне, почему эта структура Counter не будет работать? Он всегда сбрасывает значение до 0 между вызовами Incr.

type Counter = 
    struct

        val mutable i: int 

        member public this.Incr() =
            this.i <- this.i + 1

        member public this.Count = 
            this.i
    end

let noCounty(s:string): int = 
    let x = new Counter()
    x.Incr()
    x.Incr()
    x.Count

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Семантика изменяемых структур всегда сбивает с толку, потому что в некоторых ситуациях структура неожиданно копируется, когда вы используете ее определенным образом, поэтому рекомендуется избегать мутаций внутри структур.

Вы можете сделать это, пометив переменную x внутри noCounty изменяемой. Учитывая ваше текущее определение Counter, следующее работает как ожидалось:

let noCounty() = 
    let mutable x = new Counter()
    x.Incr()
    x.Incr()
    x.Count

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

let noCounty () = 
    let x = new Counter()
    (let t1 = x in t1.Incr())
    (let t2 = x in t2.Incr())
    (let t3 = x in t3.Count)

Я ожидаю, что компилятор предупредит меня об этом - поэтому, возможно, отсутствие предупреждения в этом случае следует сообщать как ошибку компилятора. (Хотя поведение, вероятно, предназначено.)

0 голосов
/ 08 ноября 2018

Если вы действительно хотите это сделать, вы можете:

[<Struct>]
type Counter = 
        val mutable i: int 

        member public this.Incr() =
            this.i <- this.i + 1

        member public this.Count = 
            this.i

let  mutable x = Counter() // You need to make the struct itself mutable
x.Incr()
x.Incr()
x.Count
//val it : int = 2

Если честно, компилятор должен пожаловаться на такое поведение. Хотя это не очень хорошая идея, чтобы мутировать в целом, и в структурах конкретно; вы можете, но вам нужно сделать сам x изменяемым, потому что вы изменяете саму структуру, которая является типом значения. Другой ответ дает вам класс, который является ссылочным типом.

0 голосов
/ 08 ноября 2018

Я не знаю, почему это не работает так, как у вас, но работает так:

type Counter() = 
    [<DefaultValue>]
    val mutable i: int

    member public this.Incr() =
        this.i <- this.i + 1

    member public this.Count = 
        this.i
...