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 = ""
我正在编写一个 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 = ""