Nim 支持自动投射吗?

Does Nim support autocasting?

我试图对序列中特定类型的对象调用函数,但编译器报错。

如何解决?我需要从 TextDoc 对象中获取 text 属性。

type
  DocItem = object of RootObj
    tags: seq[string]

  TextDoc = object of DocItem
    text: string

  TodoDoc = object of DocItem
    todo: string

var docs: seq[ref DocItem]

proc to_ref[T](o: T): ref T =
  result.new
  result[] = o

docs.add TextDoc(text: "some doc").to_ref
docs.add TodoDoc(todo: "some todo").to_ref

for d in docs:
  if d of TextDoc:
    echo d.text

错误

Error: undeclared field: 'text'

of 条件语句不会神奇地转换块其余部分的类型,我会转换类型,或者编写一个额外的辅助过程来完成它:

proc toTextDoc(thing: ref DocItem): ref TextDoc = cast[ref TextDoc](thing)
proc toTodoDoc(thing: ref DocItem): ref TodoDoc = cast[ref TodoDoc](thing)

for d in docs:
  if d of TextDoc:
    echo d.toTextDoc.text
  elif d of TodoDoc:
    echo d.toTodoDoc.todo
  else:
    echo "Not a ref?"

要对已接受的答案发表评论,cast 是一种不安全的操作,除非您有特定理由使用它,否则应避免使用它。您可以改用类型转换,如下所示:

for d in docs:
  if d of ref TextDoc:
    echo TextDoc(d[]).text

如果你使 TextDocTodoDoc ref object of DocItem 那么你可以摆脱你的 to_ref 过程,并像这样编写循环:

for d in docs:
  if d of TextDoc:
    echo TextDoc(d).text

或者您可以使用对象变体,这可能是最惯用的方法:

type
  DocType = enum dtText, dtTodo
  DocItem = ref object
    tags: seq[string]
    case kind: DocType
    of dtText: text: string
    of dtTodo: todo: string

var docs = @[DocItem(kind: dtText, text: "some doc"),
             DocItem(kind: dtTodo, todo: "some todo")]

for d in docs:
  if d.kind == dtText:
    echo d.text