2011-12-17 39 views
3

假設我有這個類:F#可選的構造來分配值(可變)let綁定

type Pet (name:string) as this = 
    let mutable age = 5 
    let mutable animal = "dog" 

我希望能夠創建一個新的Pet基於一些序列化的數據,這是我與這個紀錄代表:

type PetData = { 
    name : string 
    age : int 
    animal : string 
} 

(TLDR:我想不通的語法,以使該將採取PetData來填充let綁定構造我的各種嘗試跟隨)

因此,我創建了一個新的Pet構造函數,它將值賦給let綁定。我嘗試使用類初始化語法:

new (data:PetData) = 
    Pet(name, 
     age = data.age, 
     animal = data.animal 
    ) 

嗯,沒了:No accessible member or object constructor named 'Pet' takes 1 arguments. The named argument 'age' doesn't correspond to any argument or settable return property for any overload.

我檢查,以確保我已經得到了所有的語法:沒有丟逗號,正確的「分配」(咳嗽)操作員,正確的縮進。

好吧,我會嘗試記錄初始化器的語法。

new (data:PetData) = 
    { 
     name = data.name; 
     age = data.age; 
     animal = data.name 
    } 

錯誤:The type 'Pet' does not contain a field 'name'

好了,所以我需要調用主構造函數。我想大概有兩個地方我可以把它,所以讓我們嘗試兩種:

new (data:PetData) = 
    { 
     Pet(data.name); 
     age = data.age; 
     animal = data.name 
    } 

都能跟得上:Invalid object, sequence or record expression

new (data:PetData) = 
    Pet(data.name) 
    { 
     age = data.age; 
     animal = data.name 
    } 

而且都能跟得上:This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.

我不希望有做到這一點,但也許因爲無論如何字段是可變的,我可以在初始化它之後給對象賦值:

​​

Type constraint mismatch. The type Pet is not compatible with type PetData The type 'Pet' is not compatible with the type 'PetData'

哈哈,什麼?

好吧,讓我們試試這個:

let assign(data:PetData) = 
    this.age <- data.age 
    this.animal <- data.animal 

new (data:PetData) = 
    let p = Pet(data.name) 
    p.assign(data) 
    p 

The field, constructor or member 'assign' is not defined

對,所以它不能訪問讓綁定來自外部。

讓我們嘗試一個成員,那麼:

new (data:PetData) = 
    let p = Pet(data.name) 
    p.Assign(data) 
    p 

member x.Assign(data:PetData) = 
    this.age <- data.age 
    this.animal <- data.animal 

This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.

好了...讓我們來試試這整個事情有所不同的話,使用明確的領域:

type Pet = 
    [<DefaultValue>]val mutable private age : int 
    [<DefaultValue>]val mutable private animal : string 
    val private name : string 

    new(name:string) = 
     { name = name } 

    new(data:PetData) = 
     { 
      name = data.name; 
      age = data.age; 
      animal = data.animal 
     } 

Extraneous fields have been given values

,這時候我一拳我年邁的貓的臉。

還有其他想法嗎?這些錯誤消息讓我失望。我甚至無法在Google上找到其中的一半。

回答

3

你可以這樣做。

type Pet = 
    val mutable private age : int 
    val mutable private animal : string 
    val private name : string 

    new (name:string) = 
     { 
      name = name; 
      age = 5; // or age = Unchecked.defaultof<_>; 
      animal = "dog"; // or animal = Unchecked.defaultof<_>; 
     } 

    new (data:PetData) = 
     { 
      name = data.name; 
      age = data.age; 
      animal = data.animal; 
     } 

F#有它自己的樣式,看起來像這樣。

type Pet(name:string, age:int, animal:string) = 
    let mutable age = age 
    let mutable animal = animal 

    new (name:string) = 
     Pet(name, 5, "dog") 

    new (data:PetData) = 
     Pet(data.name, data.age, data.animal) 

編輯

添加在do採用每個評論的請求的事件。

type Pet(name:string, age:int, animal:string, start:IEvent<string>) = 
    let mutable age = age 
    let mutable animal = animal 

    // all three constructors will call this code. 
    do start.Add (fun _ -> printf "Pet was started") 

    new (name:string, start:IEvent<_>) = 
     // an example of different logic per constructor 
     // this is called before the `do` code. 
     let e = start |> Event.map (fun x -> x + " from 'name constructor'") 
     Pet(name, 5, "dog", e) 

    new (data:PetData, start:IEvent<_>) = 
     Pet(data.name, data.age, data.animal, start) 
+0

第一個工作;事實證明它正在抱怨`[]`。謝謝! – 2011-12-17 09:00:42

+0

順便說一下,我正在考慮第二個,但據我所知,你最終會得到每個字段的重複 - 這對於大量的對象來說並不好。 – 2011-12-17 09:03:41

1

讓綁定在一個類型是私人的,並沒有太多你可以做的。因此你不能使用命名參數。通過創建屬性,你可以不喜歡它的話,而不是從寵物型內:

type Pet (name:string) = 
    let mutable age = 5 
    let mutable animal = "dog" 

    member x.Age with get() = age and set v = age <- v 
    member x.Animal with get() = animal and set v = animal <- v 

type PetData = { 
    name : string 
    age : int 
    animal : string 
} 
with 
    member x.ToPet = 
     new Pet (x.name, Age = x.age, Animal = x.animal) 

另一種選擇是創建一個更一般的構造像Gradbot建議,可以直接接受PetData對象或所有三個參數。