Types 如何在Nim中存储对类型的引用?
您能否在Nim中存储对象的Types 如何在Nim中存储对类型的引用?,types,nim-lang,Types,Nim Lang,您能否在Nim中存储对象的类型,类似于在Java中使用类对象? 例如,我希望实现以下目标: let myType = someObject.type 假设.type将返回对象的类型。如果可能的话,我还希望创建可以存储hashset类型的对象,最好使用泛型来限制可以使用的类型: type System = object includes: HashSet[type[Component]] excludes: HashSet[type[Component]] 或者这在Nim中是目
类型
,类似于在Java中使用类
对象?例如,我希望实现以下目标:
let myType = someObject.type
假设.type
将返回对象的类型。如果可能的话,我还希望创建可以存储hashset
类型的对象,最好使用泛型来限制可以使用的类型:
type System = object
includes: HashSet[type[Component]]
excludes: HashSet[type[Component]]
或者这在Nim中是目前不可能的吗?如果您想限制泛型采用的类型,可以使用类型类。
例如:
# Generic type only takes string or int.
type
Foo[T: string or int] = object
x: T
var
a: Foo[string]
b: Foo[int]
#var c: Foo[float] # Compile error
# Generic proc takes any type of arguments excepts float and tuple.
proc bar[T: not (float or tuple)](x: T) = discard
bar(1)
bar("a")
#bar(1.1) # Compile error
#bar((1, 1)) # Compile error
Nim不像java那样支持反射。只能在编译时使用类型进行操作。不过,您可以做的是在编译时将所有需要的类型转换为ID,并改用ID。现在我们如何生成ID?实际上,nim有一个非常简单整洁的解决方案,它使用全局宏数据
import macrocache
type TypeID* = uint16
const nextTypeID = CacheCounter("nextTypeID")
converter typeID*(T:typedesc): TypeID =
const id = nextTypeID.value
static:
inc nextTypeID
return id.TypeID
when isMainModule:
assert float == 0
assert float == 0
assert int == 1
assert float64 == 0
assert string == 2
assert (float, int) == 3
每次为类型编译typeID时,它都将缓存的计数器状态存储在编译体中的常量中。每次编译函数时,静态块都会运行,所以每次传递不同类型时,计数器都会增加。存储类型
typedesc
类型在运行时不可用,因此无法按原样存储类型
简单的解决方案是只采用以下类型的字符串表示:
let myType = $(myObject.type)
但是,如果您有类型别名,这可能无法按您希望的方式工作
type
A = seq[int]
这里$A!=“seq[int]”
即使两者在其他方面相同且可互操作,也类似地float64
和float
已经实施了这些边缘案例,因此让我们利用这些优势:
灵活安装变体
,然后大致:
import variant
let myTypeId = someObject.getTypeId # the hash of a string representation
myTypeSet.incl myTypeId #put it in your hash set
这就结束了这个答案的功能部分,下面将详细介绍如何在尝试包含不需要的类型时静态地出错
限制可能包括的类型
如果您只对限制可继承类型感兴趣,那么这比使用TypeClass进行限制要容易一些
import variant,sets
type
TypeSetBase = HashSet[TypeId]
TypeSet*[T] = distinct TypeSetBase
proc initTypeSet*[T](): TypeSet[T] =
TypeSetBase(result).init()
proc incl*[T](ts: var TypeSet[T], x: typedesc[T]) =
TypeSetBase(result).incl getTypeId(x)
proc contains[T](ts: TypeSet[T],x: typedesc): bool =
TypeSetBase(ts).contains getTypeId(x)
type
Foo = object of RootObj
Bar = object of Foo
Baz = object of Foo
Qux = object
var includes = initTypeSet[Foo]()
includes.incl Bar
includes.incl Baz
assert Bar in includes
assert Baz in includes
assert not(Foo in includes)
#includes.incl Qux #static error
对于一般情况,这更难。Typeclasses无法实现这一点,因为人们无法实例化字体[int | float]
这是我的解决方案,使用宏为我们制作样板。这是独立的
import macros,variant,sets
type TypeSetBase = HashSet[TypeId]
macro TypeSet*(name,cls,rhs:untyped) =
let tynm = ident("TypeSet_" & cls.repr)
let initnm = ident("init_" & cls.repr)
result = quote do:
when not declared(`tynm`):
type `tynm` = distinct TypeSetBase
proc `initnm`():`tynm` =
TypeSetBase(result).init()
proc incl*(ts: var `tynm`, x:typedesc[`cls`]) =
TypeSetBase(ts).incl getTypeId(x)
proc contains*(ts: `tynm`, x:typedesc):bool =
TypeSetBase(ts).contains getTypeId(x)
var `name` = `initnm`()
import sugar#更适合procs
var x{.TypeSet.}:SomeNumber | proc
x、 包括浮动
x、 包括(整数)->整数
x、 incl()->string
#x、 包括字符串
#静态错误:
#类型不匹配:得到
断言x中的浮点
在x中断言((int)->int)
在x中断言(proc():字符串)
这还不能得到你的系统
类型,但我现在没有时间了。一旦你存储了这些类型,你想用它们做什么?@JakubDóka我想检查序列是否包含这些类型。例如,给定上面的System
对象和一个seq[Component]
,我想将序列映射到一个HashSet[type[Component]
,然后检查它是否包含系统的所有包含和所有排除。您可以轻松地将类型转换为唯一的ID,这会有帮助吗?@JakubDóka已经考虑过使用类似的东西,如果它存在的话。你能给我指一下正确的方向吗?我只找到了typetraits模块,它没有提供这种功能。无论如何,这是否意味着无法处理类型本身?您可以处理类型,但只能在编译时处理。有一种简洁明了的解决方案,将ID指定给类型。如果你愿意的话,我可以用它来推一个答案。谢谢,但我的问题不是关于泛型的。我提到它们的唯一原因是如果类型
类型支持它们(如果存在的话),那就太好了。我建议您删除这个答案,以免混淆其他用户。如果我的答案不对,我也会删除它。通常情况下,一个未被接受的答案对以后的访问者非常有帮助,请不要删除好的答案!很遗憾,不可能直接使用类型,但您提出的解决方案似乎是一个非常好的解决方案。谢谢:)不客气。一般来说,我不希望拖拽所有类型信息的开销,所以我很感激Nim在默认情况下不会这么做。但我承认,当你确实需要它/能够负担得起开销时,它应该更简单。我还意识到,在所有类型都在序列中之后,我还没有解决你这样做的需要(发帖问题)!这是另一回事,我仍然认为您应该使用变体。这也是解决我问题的有效方法,尽管它有点不可预测,因为这些ID可能会更改
import sugar # just nicer for procs
var x{.TypeSet.}:SomeNumber | proc
x.incl float
x.incl (int)->int
x.incl ()->string
#x.incl string
# static error:
# type mismatch: got <TypeSet_SomeNumber | proc, type string>
assert float in x
assert ((int)->int) in x
assert (proc():string) in x