2017-07-03 87 views

回答

13

这可以保护您免受前几年瘟疫C#世界的困扰:结构按值传递

请注意,红色波浪状(如果您在IDE中)不在FirstName之下,但不在john之下。编译器不抱怨改变john.FirstName的值,而是改变john本身的值。

对于非结构中,在参考和引用的对象之间一个重要的区别:

enter image description here

参考和对象本身可以是可变的。所以你可以改变引用(即使它指向一个不同的对象),或者你可以改变对象(即改变它的字段的内容)。

对于结构,但是,这种区别不存在,因为没有参考:

enter image description here

这意味着,当你发生变异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! 

我清楚地记得,几乎每天都在回答这个问题。那些日子!:-)

相关问题