You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌套结构体场景下Getter值未更新问题排查咨询

问题分析与解决

问题根源

核心原因是Crystal语言中struct与class的类型特性差异:

  • Counter被定义为struct,属于值类型。当你把Counter实例存入Tree的哈希表,或是从哈希表中取出时,都会生成新的副本。
  • 通过Tree调用increment时,实际操作的是哈希表中Counter的副本,原实例的total根本没被修改,所以最终看到的total始终为0。
  • 直接调用Counter实例的increment时,操作的是原实例本身,所以total能正常更新。

修复方案

把Counter从struct改为class即可——class是引用类型,赋值和传递时只会传递引用,所有操作都会作用在同一个实例上:

module CounterTree
  # 将struct改为class
  class Counter
    getter table : Hash(UInt64, UInt64)
    getter total : UInt64

    def initialize
      @table = Hash(UInt64, UInt64).new
      @total = 0_u64
    end

    def increment : UInt64
      insert(key = timestamp, value : UInt64 = 1)
    end

    def insert(key : UInt64, value : UInt64) : UInt64
      if @table.has_key?(key)
        @table[key] += value
      else
        @table[key] = value
      end
      increment_total(value)
      value
    end

    private def increment_total(value : UInt64) : UInt64
      @total += value
    end

    private def timestamp
      Time.local.to_unix_ms.to_u64
    end
  end

  struct Tree
    getter branches = [] of Hash(UInt64, CounterTree::Counter)
    getter branches_num : UInt32

    def initialize(@branches_num = 9)
      @branches = Array.new(@branches_num) do
        Hash(UInt64, CounterTree::Counter).new
      end
    end

    def increment(key : UInt64) : UInt64
      with_counter(key) do
        increment
      end
    end

    private def with_counter(key : UInt64)
      index = (key % @branches_num).to_u64
      unless @branches[index][key]?
        @branches[index][key] = Counter.new
      end
      with @branches[index][key] yield
    end
  end
end

# 测试代码保持不变
counter = CounterTree::Counter.new

counter.increment
counter.increment
counter.increment

pp counter

puts "---------"

tree = CounterTree::Tree.new

tree.increment 1234_u64
tree.increment 1234_u64
tree.increment 1234_u64

pp tree

额外说明

在Crystal中,struct适合封装不可变或简单的值类型数据;如果需要一个能被多处引用、修改状态的类型,应该使用class。这是值类型与引用类型的核心区别,也是这类状态不更新问题的常见诱因。

内容的提问来源于stack exchange,提问作者Sergey Fedorov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:25:37