当我有以下代码时:
[<Struct>]
type Person = { mutable FirstName:string ; LastName : string}
let john = { FirstName = "John"; LastName = "Connor"}
john.FirstName <- "Sarah";
Run Code Online (Sandbox Code Playgroud)
编译器抱怨"一个值必须是可变的才能改变内容".但是,当我删除Struct属性时,它工作正常.为什么会这样 ?
Fyo*_*kin 14
这可以保护你免受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
Run Code Online (Sandbox Code Playgroud)
有关进一步说明,请在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";
}
}
Run Code Online (Sandbox Code Playgroud)
IDE将有用地强调c.Person并告诉您"无法修改'SomeClass.Person'的返回值,因为它不是变量".
这是为什么?每次你写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!
Run Code Online (Sandbox Code Playgroud)
我清楚地记得几乎每天回答这个问题.那些日子!:-)