Почему t.b оценивается при каждом вызове? И можно ли каким-либо образом оценить его только один раз?
type test =
{ a: float }
member x.b =
printfn "oh no"
x.a * 2.
let t = { a = 1. }
t.b
t.b
Почему t.b оценивается при каждом вызове? И можно ли каким-либо образом оценить его только один раз?
type test =
{ a: float }
member x.b =
printfn "oh no"
x.a * 2.
let t = { a = 1. }
t.b
t.b
Это свойство; вы в основном называете членом get_b()
.
Если вы хотите, чтобы эффект выполнялся один раз с конструктором, вы можете использовать класс:
type Test(a:float) =
// constructor
let b = // compute it once, store it in a field in the class
printfn "oh no"
a * 2.
// properties
member this.A = a
member this.B = b
Альтернативная версия ответа Брайана, которая будет оценивать b
не более одного раза, но не будет ее вообще оценивать, если b
никогда не используется
type Test(a:float) =
// constructor
let b = lazy
printfn "oh no"
a * 2.
// properties
member this.A = a
member this.B = b.Value
В ответ на ваши комментарии в сообщении Брайана вы можете подделывать копии записи и обновления, используя необязательные/названные аргументы. Например:
type Person(?person:Person, ?name, ?age) =
let getExplicitOrCopiedArg arg argName copy =
match arg, person with
| Some(value), _ -> value
| None, Some(p) -> copy(p)
| None, None -> nullArg argName
let name = getExplicitOrCopiedArg name "name" (fun p -> p.Name)
let age = getExplicitOrCopiedArg age "age" (fun p -> p.Age)
member x.Name = name
member x.Age = age
let bill = new Person(name = "Bill", age = 20)
let olderBill = new Person(bill, age = 25)
printfn "Name: %s, Age: %d" bill.Name bill.Age
printfn "Name: %s, Age: %d" olderBill.Name olderBill.Age
Предыдущие ответы предполагают переход к классу вместо использования записи. Если вы хотите остаться с записями (для их простого синтаксиса и неизменности), вы можете использовать этот подход:
type test =
{ a : float
b : float }
static member initialize (t: test) =
{ t with b = t.a * 2. }
Это полезно, если экземпляр test
создается другой библиотекой (например, поставщиком данных из веб-службы или базы данных). При таком подходе вы должны помнить о том, чтобы передать любой экземпляр test
, который вы получаете из этого API, через функцию инициализации, прежде чем использовать его в своем коде.