假设我有这个课程:
type Pet (name:string) as this =
let mutable age = 5
let mutable animal = "dog"
Run Code Online (Sandbox Code Playgroud)
我希望能够Pet基于一些序列化数据创建一个新的,我用这个记录表示:
type PetData = {
name : string
age : int
animal : string
}
Run Code Online (Sandbox Code Playgroud)
(TLDR:我无法弄清楚构建一个构造函数的语法,它将PetData填充let绑定.我的各种尝试都会随之而来.)
所以我创建了一个新的Pet构造函数,它将为let绑定赋值.我尝试使用类初始化器语法:
new (data:PetData) =
Pet(name,
age = data.age,
animal = data.animal
)
Run Code Online (Sandbox Code Playgroud)
嗯,不, 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
}
Run Code Online (Sandbox Code Playgroud)
错误: The type 'Pet' does not contain a field 'name'
好的,所以我需要调用主构造函数.我想我可以放两个地方,所以让我们试试两个:
new (data:PetData) =
{
Pet(data.name);
age = data.age;
animal = data.name
}
Run Code Online (Sandbox Code Playgroud)
不: Invalid object, sequence or record expression
new (data:PetData) =
Pet(data.name)
{
age = data.age;
animal = data.name
}
Run Code Online (Sandbox Code Playgroud)
不,不: 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.
我不想这样做,但也许因为字段是可变的,我可以在初始化之后为对象分配值:
new (data:PetData) =
let p = Pet(data.name)
p.age <- data.age
p.animal <- data.animal
p
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
The field, constructor or member 'assign' is not defined
是的,所以它无法从外部访问let绑定.
让我们尝试一个成员:
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
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
Extraneous fields have been given values
那就是我把老猫打在脸上的时候.
还有其他想法吗?这些错误消息让我失望.我甚至无法在Google上找到其中一半.
你可以做到这一点。
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;
}
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
编辑
添加了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)
Run Code Online (Sandbox Code Playgroud)