假设我有这门课程:
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.
我检查以确保我已经掌握了所有语法:没有错过的逗号,正确的“赋值”( cough )运算符,正确的缩进。
好的,我会尝试记录初始化语法。
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
}
and nope: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
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
是的,所以它无法从外部访问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
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上找到其中一半。
答案 0 :(得分:4)
你可以这样做。
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)
答案 1 :(得分:1)
让类型中的绑定是私有的,你可以做的不多。因此,您不能使用命名参数。通过创建属性,您可以这样做,但不能从Pet类型内部执行:
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对象或者接受所有三个参数。