为什么结构值必须可变才能设置索引 属性?
Why must a struct value be mutable to set an indexed property?
考虑以下程序:
[<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
最后一行编译失败:
error FS0256: A value must be mutable in order to mutate the contents
or take the address of a value type, e.g. 'let mutable x = ...'
但是,如果 [<Struct>]
属性被删除,Grid2D 是引用类型,那么程序可以编译。
有趣的是,手动内联 属性 setter 也可以正常编译:
g.Data.[1 * g.RowLength + 1] <- 4
那么为什么称它为编译错误?
注意:我知道存在此编译器错误使得无法通过设置其字段之一来改变结构的非可变值。但我显然没有改变这里的结构。
我想在这里猜测它适用于该错误消息的第二部分 - "or take the address of a value type"。它不是可变性,而是值类型的 地址 需要采用,以便您在更改数据时引用相同的值 g。
编译器可能无法始终如一地证明任何 setter 实际上并没有改变结构,所以它不会打扰,只是在对非可变结构绑定使用赋值语句时总是发出错误。
换句话说,问题变成了:为什么 F# 假设 属性 setters 改变他们的实例 ?好吧,可能是因为 属性 setter 经常这样做。
内联 属性 setter 在这种情况下有效,因为赋值的目标是 属性 的元素而不是结构本身的 属性 .
考虑以下程序:
[<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
最后一行编译失败:
error FS0256: A value must be mutable in order to mutate the contents or take the address of a value type, e.g. 'let mutable x = ...'
但是,如果 [<Struct>]
属性被删除,Grid2D 是引用类型,那么程序可以编译。
有趣的是,手动内联 属性 setter 也可以正常编译:
g.Data.[1 * g.RowLength + 1] <- 4
那么为什么称它为编译错误?
注意:我知道存在此编译器错误使得无法通过设置其字段之一来改变结构的非可变值。但我显然没有改变这里的结构。
我想在这里猜测它适用于该错误消息的第二部分 - "or take the address of a value type"。它不是可变性,而是值类型的 地址 需要采用,以便您在更改数据时引用相同的值 g。
编译器可能无法始终如一地证明任何 setter 实际上并没有改变结构,所以它不会打扰,只是在对非可变结构绑定使用赋值语句时总是发出错误。
换句话说,问题变成了:为什么 F# 假设 属性 setters 改变他们的实例 ?好吧,可能是因为 属性 setter 经常这样做。
内联 属性 setter 在这种情况下有效,因为赋值的目标是 属性 的元素而不是结构本身的 属性 .