考虑以下程序:
[<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)
那么为什么称它为编译错误?
注意:我知道存在此编译器错误,因此无法通过设置其中一个字段来改变结构的非可变值.但我显然没有在这里改变结构.
编译器可能不可能一致地证明任何 setter 实际上不会改变结构,因此它不会打扰,并且在非可变结构绑定上使用赋值语句时总是发出错误。
换句话说,问题变成了:为什么 F# 假设属性设置器会改变它们的实例?嗯,可能是因为这通常是财产设定者所做的事情。
在这种情况下,内联属性设置器是有效的,因为赋值的目标是属性的元素,而不是结构本身的属性。