当我有以下代码:在F#中不允许写入结构记录的可变属性。为什么?
[<Struct>]
type Person = { mutable FirstName:string ; LastName : string}
let john = { FirstName = "John"; LastName = "Connor"}
john.FirstName <- "Sarah";
编译器抱怨“A值必须以变异的内容可变”。但是,当我删除结构属性它工作正常。为什么 ?
当我有以下代码:在F#中不允许写入结构记录的可变属性。为什么?
[<Struct>]
type Person = { mutable FirstName:string ; LastName : string}
let john = { FirstName = "John"; LastName = "Connor"}
john.FirstName <- "Sarah";
编译器抱怨“A值必须以变异的内容可变”。但是,当我删除结构属性它工作正常。为什么 ?
这可以保护您免受前几年瘟疫C#
世界的困扰:结构按值传递。
请注意,红色波浪状(如果您在IDE中)不在FirstName
之下,但不在john
之下。编译器不抱怨改变john.FirstName
的值,而是改变john
本身的值。
对于非结构中,在参考和引用的对象之间一个重要的区别:
参考和对象本身可以是可变的。所以你可以改变引用(即使它指向一个不同的对象),或者你可以改变对象(即改变它的字段的内容)。
对于结构,但是,这种区别不存在,因为没有参考:
这意味着,当你发生变异john.FirstName
,还发生变异john
本身。他们是一样的。
因此,为了执行此突变,你需要声明john
本身作为可变太:
[<Struct>]
type Person = { mutable FirstName:string ; LastName : string}
let mutable john = { FirstName = "John"; LastName = "Connor"}
john.FirstName <- "Sarah" // <-- works fine now
为了进一步说明,尝试在C#:
struct Person
{
public string FirstName;
public string LastName;
}
class SomeClass
{
public Person Person { get; } = new Person { FirstName = "John", LastName = "Smith" };
}
class Program
{
static void Main(string[] args)
{
var c = new SomeClass();
c.Person.FirstName = "Jack";
}
}
IDE将帮助下划线c.Person
并告诉您,您的“无法修改返回值'SomeClass.Person',因为它不是一个变量“。
这是为什么?每次你写c.Person
时,这被翻译成调用属性getter,就像另一种返回你的方法Person
。但由于Person
通过值传递,返回Person
将是不同的每次Person
。 getter不能返回你对同一个对象的引用,因为不能引用一个结构体。因此,对此返回值所做的任何更改都不会反映在SomeClass
内的原始Person
中。
存在这是很有帮助的编译器错误之前,很多人都这样做:
c.Person.FirstName = "Jack"; // Why the F doesn't it change? Must be compiler bug!
我清楚地记得,几乎每天都在回答这个问题。那些日子!:-)