当我有以下代码时:
[<Struct>]
type Person = { mutable FirstName:string ; LastName : string}
let john = { FirstName = "John"; LastName = "Connor"}
john.FirstName <- "Sarah";
编译器抱怨&#34;一个值必须是可变的才能改变内容&#34;。但是,当我删除Struct属性时,它工作正常。为什么会这样?
答案 0 :(得分:13)
这可以保护您免受几年前曾困扰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
并告诉您&#34;无法修改&#39; SomeClass.Person&#39;的返回值。因为它不是变量&#34; 。
为什么?每次编写c.Person
时,都会将其转换为调用属性getter,这就像另一种返回Person
的方法一样。但由于Person
是按值传递的,因此返回Person
每次都会变为Person
。 getter无法返回对同一对象的引用,因为不能引用struct。因此,您对此返回值所做的任何更改都不会反映在Person
内的原始SomeClass
中。
在此有用的编译器错误存在之前,很多人会这样做:
c.Person.FirstName = "Jack"; // Why the F doesn't it change? Must be compiler bug!
我清楚地记得几乎每天回答这个问题。那些日子! : - )