【问题标题】:F# mutable values are not mutableF# 可变值不可变
【发布时间】:2016-06-29 14:52:28
【问题描述】:

我有以下结构,它应该允许我创建,然后修改时间和值属性,这将改变私有可变值 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

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

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=...'

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

编辑

好的,我简化了我的示例,因为我认为这无关紧要,但我现在明白了。我实际上有一个 TimeDataPoints 的 LinkedList,我正在尝试改变一些节点的内容,所以我不能按照建议在本地声明它。这是我的代码:

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

我该如何解决这个问题?

【问题讨论】:

标签: struct f# mutable


【解决方案1】:

您还需要将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

问题更新后编辑:如 cmets 中所述,如果您取消 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

【讨论】:

  • 你能发布一个完整的问题重现吗?
  • TimeDataPoint 存储的变量只需要在TimeDataPoint 是结构体时是可变的。如果它是一个类,则该变量将包含对该类实例的引用,并且当修改该类的属性时,该引用不需要更改。对于没有引用的结构,数据就存储在变量中,因此修改结构意味着修改变量,这就是变量本身需要可变的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 2012-06-24
  • 1970-01-01
  • 1970-01-01
  • 2014-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多