Jsony newHook 有 `SIGSEGV:非法存储访问。 (尝试从 nil 中读取?)` 反序列化为 ref-objects 时

Jsony newHook has `SIGSEGV: Illegal storage access. (Attempt to read from nil?)` when deserializing into ref-objects

我正在编写一个 Web 应用程序并通过 jsony 反序列化为规范模型对象类型。 规范模型类型始终是 ref 对象。不知何故,我的代码与 jsony github 文档中的默认示例非常相似,无法编译。相反,我收到错误 SIGSEGV: Illegal storage access. (Attempt to read from nil?).

在这里查看我的代码示例

import std/[typetraits, times]
import norm/[pragmas, model]
import jsony

const OUTPUT_TIME_FORMAT* = "yyyy-MM-dd'T'HH:mm:ss'.'ffffff'Z'"
type Character* {.tableName: "wikientries_character".} = ref object of Model
    name*: string
    creation_datetime*: DateTime
    update_datetime*: DateTime

proc parseHook*(s: string, i: var int, v: var DateTime) =
    ##[ jsony-hook that is automatically called to convert a json-string to datetime
    
    ``s``: The full JSON string that needs to be serialized. Your type may only be a part of this
    ``i``: The index on the JSON string where the next section of it starts that needs to be serialized here
    ``v``: The variable to fill with a proper value]##
    var str: string
    s.parseHook(i, str)
    v = parse(s, OUTPUT_TIME_FORMAT, utc())

proc newHook*(entry: var Character) =
  let currentDateTime: DateTime = now()
  entry.creation_datetime = currentDateTime # <-- This line is listed as the reason for the sigsev
  entry.update_datetime = currentDateTime
  entry.name = ""
  
var input = """ {"name":"Test"} """

let c = input.fromJson(Character)

我不明白这里的问题是什么,因为其 github 页面上的 jsony-example 看起来非常相似:

type
  Foo5 = object
    visible: string
    id: string
proc newHook*(foo: var Foo5) =
  # Populates the object before its fully deserialized.
  foo.visible = "yes"

var s = """{"id":"123"}"""
var v = s.fromJson(Foo5)
doAssert v.id == "123"
doAssert v.visible == "yes"

我该如何解决这个问题?

答案在于 norm-object-types 是 ref 对象 ,而不是普通(值)对象(感谢来自 [=23 的 ElegantBeef、Rika 和 Yardanico =] 指出这一点)!如果您在某一时刻没有显式 'create' a ref-type,则永远不会分配它的内存,因为代码不会为您分配内存,这与值类型不同!

所以必须先initialize/create一个ref-object才能使用,Jsony不会替你接手初始化!

上面newHook的正确写法是这样的:

proc newHook*(entry: var Character) =
  entry = new(Character)
  let currentDateTime: DateTime = now()
  entry.creation_datetime = currentDateTime
  entry.update_datetime = currentDateTime
  entry.name = ""