【问题标题】:Pass by reference in Red routines在 Red 例程中通过引用传递
【发布时间】:2015-05-06 20:57:31
【问题描述】:

所以我目前正在将一个下降大小的程序从 Rebol 3 迁移到 Red。所述程序依赖于与 C 库 (clang) 的大型绑定。我已经重写了 Red/System 中的绑定部分,并通过包装例程将该代码与 Red 连接。我一直在使用的当前约定是将需要作为参数并由 C 代码返回的指针和 void 指针转换为红色/系统整数并将它们装箱为红色整数。这相当简单方便。

因为我只能访问原始整数! data 而不是实际的结构,我会怀疑我不能再使用上述方法通过参数将指针传回(因为在传递之前正在复制装箱的数据)。

那么,有没有推荐的方法来通过参数将指针传回,也就是我们如何通过例程的引用传递?

twiddle: routine [
    arg [integer!]
    return: [integer!]
] [
    arg: 321
    test: declare struct! [
        dummy [integer!]
    ]
    test/dummy: 456
    as integer! test
]

a: 123
b: twiddle a

print a ;If I could pass by reference this would be 321
print b

【问题讨论】:

  • 您能否编辑以提供您以前有效但现在无效的代码,并提及改变行为的特定版本号?
  • 我认为实际上可能发生的情况是,我使用的旧版本可能是一个自动构建,但封送处理损坏,因为我已经回顾并检查了以前的发行版本。

标签: red red-system


【解决方案1】:

当您执行twiddle a 时,您不会将单词a 传递给函数,而是传递它的值。类似 Rebol 的语言中的词与许多其他语言中的变量并不完全一样。它们是第一类值,可以引用上下文中的其他值,也就是 namespace。所以一个词不包含任何值,它指向一个包含该值的上下文表。您可以将上下文想象成一个包含两列的表,左列包含单词,右列包含它们各自的值。

所以,严格来说,不存在“通过引用传递”,您只能在 Red 级别操作 ,并且这些值始终从上下文表复制到 Red 内部堆栈。如果要更改a 引用的值,则需要将a 设置为该新值。这也可以使用 Red 运行时 API 在 Red/System 级别实现,但该 API 目前是非正式的,并且没有完全稳定(但无论如何在内部大量使用)。

处理您的需求的一个好方法是构建一个值块,而不是为单词分配单个值,但我对您想要实现的目标的了解不够,无法确定它是否适合。

所以在这个序言之后,更直接地回答你的问题:你不能通过引用传递一个例程,你只能通过值传递(要么得到一个编组的值,要么得到一个指向装箱值的指针在堆栈上,而不是在上下文表中)。如果该值恰好是一个像块一样的系列!例如,您可以从例程中修改其内容(如更改、添加、删除元素)。

无论如何,如果你真的想从例程中更改单词引用的值,这里是如何实现它:

twiddle: routine [
    w [word!]
    return: [integer!]
    /local test
] [
    test: declare struct! [
        dummy [integer!]
    ]
    test/dummy: 456
    _context/set w as red-value! integer/box as-integer test
    as integer! test
]

a: 123
b: twiddle 'a

如您所见,您需要传递一个未评估的单词(一个 lit-word!),然后从例程中设置它的值,以实现您所期望的副作用。但这不是推荐的方式,最好使用块!或对象!将值从 Red/System 级别推送到 Red 级别,或者只是将返回的值分配给一个单词,就像为 b 所做的那样。

希望这会有所帮助。

【讨论】:

  • 谢谢医生!我想了很多,我只是不知道如何在上下文中设置值。在这一点上,我只是试图让 Red 代码尽可能接近 Rebol,然后一旦它的功能开始重构,使其更加“正确”。
  • @johnk 感谢您修复错别字。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-20
  • 1970-01-01
  • 2013-11-05
  • 2011-01-14
  • 2015-01-15
相关资源
最近更新 更多