为什么结构值必须是可变的才能设置索引属性?

时间:2015-07-04 04:34:50

标签: f#

考虑以下计划:

[<Struct>]
type Grid2D<'T> = 
    val RowLength : int
    val Data : 'T[]
    new(rowLength, data) = { RowLength = rowLength; Data = data }

    member this.Item
        with get(rowIndex, columnIndex) = 
            this.Data.[rowIndex * this.RowLength + columnIndex]
        and set(rowIndex, columnIndex) value = 
            this.Data.[rowIndex * this.RowLength + columnIndex] <- value

let g = Grid2D(3, Array.zeroCreate(3 * 3))
g.[1, 1] <- 4

最后一行无法编译:

  

错误FS0256:值必须是可变的才能改变内容   或者获取值类型的地址,例如&#39;让mutable x = ...&#39;

但是,如果删除[<Struct>]属性,并且Grid2D因此是引用类型,则程序将编译。

有趣的是,手动内联属性设置器也可以很好地编译:

g.Data.[1 * g.RowLength + 1] <- 4

那么为什么称它为编译错误?

注意:我知道存在此编译器错误,因此无法通过设置其中一个字段来改变结构的非可变值。但我在这里显然没有改变结构。

2 个答案:

答案 0 :(得分:0)

我想在这里猜一下,该错误信息的第二部分适用于 - &#34;或者取值类型的地址&#34;。它不是可变性,而是需要采用的值类型的地址,以便在改变数据时引用相同的值g。

答案 1 :(得分:0)

编译器可能不可能始终如一地证明任何setter实际上都没有改变结构,因此它不会在使用非可变结构上的赋值语句时发生错误并且总是发出错误绑定。

换句话说,问题变成:为什么F#假设属性设定者改变他们的实例?好吧,可能是因为这通常是财产制定者所做的事情。

在这种情况下内联属性setter是有效的,因为赋值的目标是属性的元素而不是struct本身的属性。