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

Asi*_*sik 7 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
Run Code Online (Sandbox Code Playgroud)

最后一行无法编译:

错误FS0256:值必须是可变的才能改变内容或获取值类型的地址,例如'let mutable x = ...'

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

有趣的是,手动内联属性setter也很好:

g.Data.[1 * g.RowLength + 1] <- 4
Run Code Online (Sandbox Code Playgroud)

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

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

Asi*_*sik 0

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

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

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