Nim - 如何在编译时访问类型为 Option[mytype] 的字段的 mytype?

Nim - How to access mytype of a field that has the type Option[mytype] at compile time?

嘿嘿,

在通过一些泛型编写代码时,我偶然发现了我的一个泛型函数的问题。 我有 2 种类型,比如这个

import std/options
import norm

type
    A = ref object of Model
        name: string
    B = ref object of Model
        name: string
        myA: Option[A]

norm,nim 中用于 sqlite 的 ORM,我可以通过具有类型在编译时获取模型所属的 sql-表名继承自 Model 并在其上调用 table()

出于各种原因,我希望能够找出给定模型链接到的所有表的名称。在这种情况下,B 链接到 A 类型,但我需要在编译时调用 A.table() 来获取该表名(如果 {.tableName.} 编译指示可以是任何内容正在使用中)。

但是,我似乎找不到访问我的类型的方法,因为我无法在编译时调用 options 模块的典型 get() 方法。我的出路在哪里?

感谢 nim-discord 服务器上的热心帮助(大声喊叫 leorize),我才得以解决这个问题。事实上,我提出这个问题只是为了让我自己 google 更容易回答。

有多种方法可以解决这个问题:

  1. 尝试直接访问类型

Option的泛型参数称为T。其中 T 是您要查找的类型。

proc getRelatedFieldName[M: Model, O:Model](targetType: typedesc[O], sourceType: typedesc[M]): Option[string] =
    let source = sourceType()
    for sourceFieldName, sourceFieldValue in source[].fieldPairs:
        when sourceFieldValue is Option:
            when sourceFieldValue.get() is Model:
                when O.table() == sourceFieldValue.T.table():
                    return some(sourceFieldName) 

    return none(string)


echo A.getRelatedFieldName(B) # returns "some('myA')"

如果您使用的不是 typedesc 而是实际类型,您可能需要考虑使用 typeof(sourceFieldValue).T.table()

  1. 使用typetraitgenericParams函数

您可以使用 [typetraits][1] 库及其 genericParams 函数。

genericParams(B).get(0)

使用 genericParams 作为工具,您可以做一些有趣的事情,比如在编译时迭代一个类型的所有字段(不是实例!),检查给定字段是否是模型的选项并比较表名

proc getRelatedFieldName[M: Model, O:Model](targetType: typedesc[O], sourceType: typedesc[M]): Option[string] =
    let source = sourceType()
    for sourceFieldName, sourceFieldValue in source[].fieldPairs:
        when sourceFieldValue is Option:
            when sourceFieldValue.get() is Model:
                when O.table() == genericParams(sourceFieldValue.type()).get(0).table():
                    return some(sourceFieldName) 

    return none(string)


echo A.getRelatedFieldName(B) # returns "some('myA')"