F#可变值不可变

时间:2016-06-29 14:52:29

标签: struct f# mutable

我有以下结构,它应该允许我创建,然后修改时间和值属性,这将改变私有可变值x.Time_和x.Value _。

type TimeDataPoint = 
    struct
        val mutable private Time_: DateTime
        val mutable private Value_: double

        new (time: DateTime, value: double) = 
            {
                Time_ = time
                Value_ = value
            }

        member public x.Time
            with get() = x.Time_
            and set(time: DateTime) = x.Time_ <- time

        member public x.Value
            with get() = x.Value_
            and set(value: double) = x.Value_ <- value

    end

但是,当我尝试在以后的代码中使用其中一个setter时:

let tdp = TimeDataPoint(DateTime.Now, 0.0)
tdp.Time <- DateTime.Now

我收到错误:

Invalid mutation of a constant expression. Consider copying the expression to a mutable local, e.g. 'let mutable x=...'

这对我来说没有意义,因为变量已经是可变的,并且struct编译。我错过了什么?

修改

好的,我简化了我的例子,因为我认为这没关系,但我现在看到它确实如此。我实际上有一个TimeDataPoints的LinkedList,我试图改变一些节点的内容,所以我不能按照建议在本地声明它。这是我的代码:

let myList = LinkedList<TimeDataPoint>()
myList.AddFirst(TimeDataPoint(DateTime.Now, 0.0))
myList.First.Value.Value <- 1.0

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

您还需要将tdp标记为可变。剥离代码在下面,输出:

Ticks is 0
Ticks is 636028131920527873

正如所料。

module Mutation
open System
type TimeDataPoint = 
    struct
        val mutable private Time_: DateTime
        new (time: DateTime) = 
            {
                Time_ = time
            }
        member public x.Time
            with get() = x.Time_
            and set(time: DateTime) = x.Time_ <- time
    end

let usingTdp() = 
    let mutable tdp = TimeDataPoint()
    printfn "Ticks is %i" tdp.Time.Ticks
    tdp.Time <- DateTime.Now
    printfn "Ticks is %i" tdp.Time.Ticks

在更新问题后进行编辑:正如评论中所提到的,如果您取消struct这一事物,所有内容都会正常运行,例如:

type TimeDataPoint = 
    val mutable private _v: int
    new (v: int) = 
        {
            _v = v
        }
    member public this.Value
        with get() = this._v
        and set(v: int) = this._v <- v

let myList = LinkedList<TimeDataPoint>()
myList.AddFirst(TimeDataPoint(1)) |> ignore
myList.First.Value.Value <- 1

如果使用F#,你也可以考虑重新思考变异是否真的是你唯一的选择 - 我怀疑它是不是。

PS:如果您决定坚持使用变异对象,请考虑使用自动属性语法,该语法允许您将类定义缩短为:

type TimeDataPoint(v, d) = 
    member val Value: int = v with get, set
    member val Time: DateTime = d with get, set