gpt4 book ai didi

crystal-lang - 如何在 Crystal 中进行通用内存?

转载 作者:行者123 更新时间:2023-12-04 01:03:00 25 4
gpt4 key购买 nike

我想在 Crystal 中定义一个通用的内存包装器。我有以下 Crystal 代码:

  module Scalar(T)
abstract def value: T
end

class ScSticky(T)
include Scalar(T)

def initialize(sc : Scalar(T))
@sc = sc
@val = uninitialized T
end

def value: T
@val ||= @sc.value
end
end

换句话说,我希望 ScSticky 只调用底层 Scalar(T) 一次,并为所有后续调用返回缓存的输出。但是,如果 TInt32

,则上述方法不起作用

比如包装这个类的时候


class ScCounter
include Scalar(Int32)

def initialize
@val = 100
end

def value: Int32
@val += 1
@val
end
end

ScSticky(ScCounter.new).value 将始终等于 0(据我了解,因为 unitialized Int32 实际上是用 0 值初始化)

我非常感谢能帮助解决这个问题

Upd:似乎实现它的正确方法是使用 nil ,但是我在理解这样的实现应该是什么样子时遇到了问题。我还希望能够记住 .value 方法,即使它返回 nil (换句话说,如果 T 是 nilable 类型)

最佳答案

你正在使用一个不安全的特性“uninitialized”,这意味着,“保留之前内存中的任何内容”(理论上该值是随机的并且可能无效,在实践中你经常以0 无论如何——但仍然不能保证。
关于未初始化 功能的简短故事是请永远不要使用它

如果您编写了 @val = 0,您就不会对此行为感到惊讶——这就是您编写的内容。

你必须定义 @val : T? = nil -- 使其变为 nilable(具有 nil 的单独可能值,这是它自己的类型 - Nil)。
您可能认为 unitialized 会带来 nil,但事实并非如此。


为了回应您关于将 nil 也包含在可能值中的评论,这里有一个完整的解决方案,它使用用户永远无法创建的独特“sentinel”结构代替 Nil。

module Scalar(T)
abstract def value: T
end

private struct Sentinel
end

class ScSticky(T)
include Scalar(T)

@val : T | Sentinel = Sentinel.new

def initialize(@sc : Scalar(T))
end

def value: T
val = @val
if val.is_a?(Sentinel)
@val = @sc.value
else
val
end
end
end

class ScCounter
include Scalar(Int32)

def initialize
@val = 100
end

def value: Int32
@val += 1
end
end

sc = ScSticky.new(ScCounter.new)

p! sc.value #=> 101
p! sc.value #=> 101

关于crystal-lang - 如何在 Crystal 中进行通用内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67560487/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com