Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#更改对象的状态_F#_Pass By Reference_Immutability_Record_Mutable - Fatal编程技术网

F#更改对象的状态

F#更改对象的状态,f#,pass-by-reference,immutability,record,mutable,F#,Pass By Reference,Immutability,Record,Mutable,我有一个模拟器,它用两个成员记录一些状态:一个是Class1对象,另一个是Class2对象序列 模拟运行时,将读取输入,并根据输入调用这些对象的某些方法。这种方法改变了它们的内部状态 我正在学习F#,我理解不可变数据的重要性。然而,考虑到这种状态的复杂性(比这里公开的要复杂得多),我认为拥有这种具有内部可变状态的对象并不是什么大问题。至少它是隐藏的 然而,问题是另一个。这可能很简单 在迭代之间,我丢失了对“一”和“多”对象的更改 我猜InvokeMethodOn(显然是简化的)会复制这些对象 我

我有一个模拟器,它用两个成员记录一些状态:一个是Class1对象,另一个是Class2对象序列

模拟运行时,将读取输入,并根据输入调用这些对象的某些方法。这种方法改变了它们的内部状态

我正在学习F#,我理解不可变数据的重要性。然而,考虑到这种状态的复杂性(比这里公开的要复杂得多),我认为拥有这种具有内部可变状态的对象并不是什么大问题。至少它是隐藏的

然而,问题是另一个。这可能很简单

在迭代之间,我丢失了对“一”和“多”对象的更改

我猜InvokeMethodOn(显然是简化的)会复制这些对象

我知道我需要一些参考资料,但是。。。我在这里有点迷路了。。。州应该有ref成员吗?InvokeMethodOn应该通过ref传递吗?都是吗?那么“多”序列呢

编辑:可能有数百万个“多”对象。它们中的每一个都有1或2kb的状态(目前只保存在一个字节块中)

编辑:将“many”更改为数组(并按照建议使用array.iter)修复了该问题。谢谢大家

type State = {
    one : Class1
    many : Class2 seq
}

type Simulator() = class
    member x.run(state : State) =
        // ....
        while ...
            let input = ReadInput
            if someFuncOf(input)
                then InvokeMethodOn(state.one, input)
                else Seq.iter (fun x -> InvokeMethodOn(x, input)) state.many                

    member x.InvokeMethodOn obj input =
         obj.ChangeInternalState input
在迭代之间,我丢失了对“一”和“多”对象的更改

我猜InvokeMethodOn(显然是简化的)会复制这些对象

你猜错了
InvokeMethodOn
仅修改
Class1
Class2
的当前状态。假设每个迭代都有一个
状态
记录。因为您没有在任何地方创建新的
Class1
Class2
实例,所以这些记录都指向相同的类实例,并且在每次迭代中都以相同的方式进行修改

我认为拥有这种内部状态可变的对象并不是什么大问题。至少它是隐藏的

这是一件大事。您的隐藏状态被泄漏并导致错误行为。我相信您担心的是性能,所以您希望改变
Class1
Class2
的状态。我不知道“通过推荐”能帮你什么忙。一个简单的解决方法是写

member x.InvokeMethodOn obj input =
         obj.CreateNewInstanceWith input
并将
while
更改为某种类型的
Seq.fold
,通过调用字段上的
InvokeMethodOn
返回新的
状态

我认为最好是将
Class1
Class2
声明为记录,并将
块一起使用:
{Class1 with value=newValue}
。如果以后需要进行性能优化,您始终可以将记录更改为具有可变字段。此外,不要将
seq
声明为记录字段,这会破坏记录的结构平等性

在迭代之间,我丢失了对“一”和“多”对象的更改

我猜InvokeMethodOn(显然是简化的)会复制这些对象

你猜错了
InvokeMethodOn
仅修改
Class1
Class2
的当前状态。假设每个迭代都有一个
状态
记录。因为您没有在任何地方创建新的
Class1
Class2
实例,所以这些记录都指向相同的类实例,并且在每次迭代中都以相同的方式进行修改

我认为拥有这种内部状态可变的对象并不是什么大问题。至少它是隐藏的

这是一件大事。您的隐藏状态被泄漏并导致错误行为。我相信您担心的是性能,所以您希望改变
Class1
Class2
的状态。我不知道“通过推荐”能帮你什么忙。一个简单的解决方法是写

member x.InvokeMethodOn obj input =
         obj.CreateNewInstanceWith input
并将
while
更改为某种类型的
Seq.fold
,通过调用字段上的
InvokeMethodOn
返回新的
状态


我认为最好是将
Class1
Class2
声明为记录,并将
块一起使用:
{Class1 with value=newValue}
。如果以后需要进行性能优化,您始终可以将记录更改为具有可变字段。此外,不要将
seq
声明为记录字段,它会破坏记录上的结构平等性。

如果您的Class1和Class2包含您更改的可变状态,我看不出在每次迭代中放弃此类更改的原因,除非您以某种方式重新创建Class1的新副本

如果我尝试编写一个与所呈现内容类似的脚本,它将被罚款。 了解您的代码如何偏离这一点,以发现我们遗漏了什么,这将是一件有趣的事情

type Class1 = { mutable label : string}
type Container = { one : Class1; many : Class1 seq}

let a = { label = "a" }
let bs = [ { label = "b1" } ; { label = "b2" }]

let cont = { one =a ; many = bs}
printfn  "%A" cont.one.label

cont.one.label <- "changed a"
cont.many |> Seq.iter (fun x -> x.label <- "changed b")
printfn  "%A" cont

cont.one.label <- "changed again a"
printfn  "%A" cont
您可能想阅读本页关于 它没有什么魔力,它应该澄清很多事情


关于可变数据,还有一件事需要注意:数组在默认情况下是可变的:不需要重新声明它们是可变的。

如果您的Class1和Class2包含您更改的可变状态,我看不出为什么在每次迭代中都会丢弃这样的更改,除非您以某种方式重新创建Class1的新副本

如果我尝试编写一个与所呈现内容类似的脚本,它将被罚款。 了解您的代码如何偏离这一点,以发现我们遗漏了什么,这将是一件有趣的事情

type Class1 = { mutable label : string}
type Container = { one : Class1; many : Class1 seq}

let a = { label = "a" }
let bs = [ { label = "b1" } ; { label = "b2" }]

let cont = { one =a ; many = bs}
printfn  "%A" cont.one.label

cont.one.label <- "changed a"
cont.many |> Seq.iter (fun x -> x.label <- "changed b")
printfn  "%A" cont

cont.one.label <- "changed again a"
printfn  "%A" cont
您可能想阅读本页关于 它没有什么魔力,它应该澄清很多事情


关于可变数据,还有一点需要注意:数组在默认情况下是可变的:不需要重新声明它们是可变的。

您的
ChangeInternalState
可能有问题,对于
seq
你需要小心,因为
seq
是懒惰的-最好使用数组/列表,而不是可能的相关问题:请参考Joh的答案。简单地说,for循环在这里会更好。如果
obj.ChangeInternalState
只更改
Class2