當我有以下代碼:在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!
我清楚地記得,幾乎每天都在回答這個問題。那些日子!:-)