我想在F#对象表达式中有一个可变状态。 第一种方法是使用ref单元格如下:
type PP =
abstract member A : int
let foo =
let a = ref 0
{ new PP with
member x.A =
let ret = !a
a := !a + 1
ret
}
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
另一种方法如下:
type State(s : int) =
let mutable intState = s
member x.state
with get () = intState
and set v = intState <- v
[<AbstractClass>]
type PPP(state : State) =
abstract member A : int
member x.state
with get () = state.state
and set v = state.state <- v
let bar n =
{ new PPP(State(n)) with
member x.A =
let ret = x.state
x.state <- ret + 1
ret
}
let barA1 = bar 0
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
哪个版本的性能可能更高(我需要更新状态x.state&lt; - ret + 1 在性能关键部分)?我的猜测是State对象也在堆上分配,所以没有理由为什么第二个版本应该更快。但是使用它会更有吸引力。
感谢您的任何反馈和建议
答案 0 :(得分:5)
正如丹尼尔所说,最后一种方法基本上等同于使用内置ref
。
使用ref
时,您要分配两个对象 - 您要返回的对象和参考单元本身。您可以通过使用具体实现将此减少为仅一个已分配的对象(但我认为这在实践中不重要):
type Stateful(initial:int) =
let mutable state = initial
interface PP with
member x.A =
let ret = state
state <- state + 1
ret
let foo =
Statefull(0) :> PP // Creates a single object that keeps the state as mutable field
除此之外,您正在使用只读属性来修改对象的内部状态,并且每次都返回一个新状态。这是一个非常混乱的危险模式 - 带有getter的属性不应该修改状态,所以你应该使用方法(unit -> int
)代替。
答案 1 :(得分:3)
您的State
课程与ref
相同。它们都是引用类型(您无法从对象表达式中捕获可变值类型)。我希望在可能的情况下使用内置类型。 ref
是表示堆分配的可变值的惯用方法。
如果对性能有任何疑问,请对其进行基准测试。