【发布时间】:2017-06-11 11:03:49
【问题描述】:
我进行了很多搜索,阅读了函数式编程,但似乎无法为我的问题找到一个直接的答案。我正在用 Swift 创建一个游戏实用程序库,并且我了解限制可变性的概念,但我正在努力为简单的 PRNG 找到一个好的实现。如果我有以下代码
public struct SplitMix64 {
var seed: UInt64
public mutating func nextUInt64() -> UInt64 {
seed = seed &+ 0x9E3779B97F4A7C15
var z: UInt64 = (seed ^ (seed >> 30)) &* 0xBF58476D1CE4E5B9
z = (z ^ (z >> 27)) &* 0x94D049BB133111EB
return z ^ (z >> 31)
}
}
这可行,但如果我必须将它作为函数参数传递,则会导致问题,要么我必须在任何地方使用 inout 装饰(通过引用传递值),这意味着其他结构函数会发生变异(它像病毒一样通过您的代码)并在您想使用变异函数但不关心更新的状态时会导致编译器错误,如果将其传递给没有 inout let random=SplitMix64(SplitMix64(1).nextUInt64()) 的函数,则会将其丢弃。
我知道我可以以更实用的方式实现它,例如
public static func nextUInt64(state: UInt64) -> (state: UInt64, value: UInt64) {
let newState = state &+ 0x9E3779B97F4A7C15
var z: UInt64 = (newState ^ (newState >> 30)) &* 0xBF58476D1CE4E5B9
z = (z ^ (z >> 27)) &* 0x94D049BB133111EB
return (state: newState, value: z ^ (z >> 31))
}
但这只会给我的库的用户带来更多问题,而不是调用函数并获取值,他们现在负责跟踪状态,将其传入,并在返回时将其存储并提取从元组生成的数字。而这只是一个简单的函数,其他的生成器有更多的状态数据。我也可以像这样在状态上使用 inout 来保存元组返回
public static func nextUInt64(state: inout UInt64) -> UInt64 {
state = state &+ 0x9E3779B97F4A7C15
var z: UInt64 = (state ^ (state >> 30)) &* 0xBF58476D1CE4E5B9
z = (z ^ (z >> 27)) &* 0x94D049BB133111EB
return z ^ (z >> 31)
}
但是,当从外部调用时,发生的事情可能并不明显
例如let rand=nextUInt64(&currentState),因为只有 & 告诉您它可能会更新 currentState,并且仍然需要用户跟踪变异值,所以我不确定它是否是一个干净的设计。
当然,在这种情况下,我可以只使用一个类,但是这样我就失去了 Swift 中值类型的好处,而且大多数引擎都使用具有值类型的数组——当你有来自值结构到类。
我的问题是 - 有没有更好的方法在 Swift 中实现它 - 我知道它不是一种函数式语言,而且我对 OOP 没有任何问题。任何想法/指针都非常感谢!
【问题讨论】:
标签: swift function oop design-patterns functional-programming