克隆类实例,只更改一些属性

NoI*_*his 11 f# clone

我想知道在F#中是否有一些糖来克隆一个只改变一个或几个属性的类实例.

我知道在F#中可以使用记录:

let p2 = {p1 with Y = 0.0}
Run Code Online (Sandbox Code Playgroud)

Dan*_*iel 11

模拟类的复制和更新表达式的一种方法是使用带有可选args的复制构造函数.

type Person(first, last, age) =
  new (prototype: Person, ?first, ?last, ?age) =
    Person(defaultArg first prototype.First, 
           defaultArg last prototype.Last, 
           defaultArg age prototype.Age)
  member val First = first
  member val Last = last
  member val Age = age

let john = Person("John", "Doe", 45)
let jane = Person(john, first="Jane")
Run Code Online (Sandbox Code Playgroud)

编辑

你没有要求这个,但在许多情况下,使类可变导致更清晰的代码:

type Person(first, last, age) =
  member val First = first with get, set
  member val Last = last with get, set
  member val Age = age with get, set
  member this.Clone() = this.MemberwiseClone() :?> Person

let john = Person("John", "Doe", 45)
let jane = john.Clone() in jane.First <- "Jane"
Run Code Online (Sandbox Code Playgroud)

  • 好主意.然而,我很惊讶没有一个惯用的表达来实现这一点. (2认同)

hoc*_*cho 6

另一种选择是将记录包装在一个类中.就像是

type PersonState = { FirstName : string; LastName : string; }

type Person private (state : PersonState) =

    new (firstName, lastName) = 
        Person({ FirstName = firstName; LastName = lastName })

    member this.WithFirstName value =  
        Person { state with FirstName = value } 

    member this.WithLastName value  =  
        Person { state with LastName = value } 

    member this.FirstName with get () = state.FirstName
    member this.LastName with get () = state.LastName
Run Code Online (Sandbox Code Playgroud)

用于

let JohnDoe = Person("John", "Doe")
let JaneDoe = JohnDoe.WithFirstName "Jane" 
let JaneLastName = JaneDoe.LastName
Run Code Online (Sandbox Code Playgroud)

这种方法避免了明确的克隆和可变性.