首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在nim中创建不同过程的查找表?

如何在nim中创建不同过程的查找表?
EN

Stack Overflow用户
提问于 2021-07-01 22:58:00
回答 1查看 253关注 0票数 0

在python中,函数是“一级公民”,可以作为参数传递给函数/方法。

假设我想在python中开始编写一个基本的远程过程调用(Rpc)库,我可能首先创建一个将函数名映射到实际函数对象的字典:

代码语言:javascript
复制
rpc = {}  # string: function


def register_rpc(name, function):
    """ Register a function as a RPC """
    rpc[name] = function


def sum_nums(a, b):
    """ Sum numbers """
    return a + b


register_rpc("sum_nums", sum_nums) # register sum_nums as RPC

print(rpc["sum_nums"](10, 15))

我可以在尼姆接近这个。问题是,我必须在查找表中显式定义proc的参数和参数类型,这也必须与register_rpc过程的定义相匹配。这是我的半等效尼姆代码:

代码语言:javascript
复制
import tables


var rpc = initTable[string, proc(a, b: int): int]()  # explicitly defined procedure arguments/types


# Procedure arguments/types must match Table's proc definition or else I can't register a RPC
proc register_rpc(p: proc(a, b: int): int, n: string): bool =
    #[ Register a function as a RPC ]#
    rpc[n] = p
    true


# proc definition matches Table/register_rpc
proc sum_nums(a, b: int): int =
    #[ Sum numbers ]#
    a + b


discard register_rpc(sum_nums, "sum_nums")
echo rpc["sum_nums"](10, 15)

是否有任何方法可以创建register_rpc过程,而不必显式地定义proc参数及其类型?我怎样才能让我的Table和这个相匹配呢?昨天,我问了一个问题,这似乎是半相关的:

Can I unpack varargs to use as individual procedure call arguments with nim?

但是,我无法将untyped类型用于Table

我是否需要重载register_rpc过程以涵盖所有不同的type场景?如何在不显式定义proc参数/类型的情况下创建查找表?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-03 08:10:09

这种处理事物的动态方式在nim中不受支持。编译时必须知道proc的类型,这只是事实。当然,你可以做一些可怕和令人不快的事情,比如:

代码语言:javascript
复制
import tables

var table = initTable[string, pointer]()

table.add("add", cast[pointer](proc(a: int, b: int): int =
  a + b
))

table.add("negate", cast[pointer](proc(a: int): int =
  -a
))

assert cast[proc(a: int, b: int): int {.cdecl.}](table["add"])(10, 20) == 30

但老实说,如果你不小心投错了路,你就完了。在这种情况下,我们需要安全,一种区分指针的方法。这就是抽象出现的原因。

代码语言:javascript
复制
import macrocache, options

const counter = CacheCounter("counter")

func typeID(tp: type): int =
  const id = counter.value
  static: counter.inc
  id

{.pragma: dynProc, cdecl, noSideEffect, gcsafe, locks:0.}

type
  DynamicProc* = object
    id: int
    value: pointer

func initDynamicProc*[T](p: T): DynamicProc =
  DynamicProc(id: T.typeID, value: cast[pointer](p))

template ID*(d: DynamicProc): int = d.id

func get*(d: DynamicProc, tp: type): Option[tp] =
  if tp.typeID != d.id:
    none(tp)
  else:
    some(cast[tp](d.value))

var safeTable = initTable[string, DynamicProc]()

safeTable.add("add", initDynamicProc(proc (a, b: int): int {.dynProc.} =
  a + b
))

assert safeTable["add"].get(proc (a, b: int): int {.dynProc.}).get()(10, 20) == 30
assert safeTable["add"].get(proc (b: int) {.dynProc.}) == none(proc (b: int) {.dynProc.}) 

它仍然冗长,但这一次你必须保证它的安全。需要使用dynProc杂注来修正类型匹配,因为不同类型的类型被认为是不同的类型。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68217774

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档