【问题标题】:How to pass value from Red/System to Red?如何将值从 Red/System 传递给 Red?
【发布时间】:2020-06-16 13:58:06
【问题描述】:

我需要将我在 Red/System 中生成的值传递给 Red。我发现了文档,但没有找到如何使用它的示例。这是我的代码:

Red []

#system [   
    data!: alias struct! [
        a   [integer!]
        b   [c-string!]
    ] 

    data: declare data!

    _foo: func [return: [data!]]
    [
        data/a: 123
        data/b: "Hello"
        return data
    ]

]

sqlite: context
 [

    my-red-block: []; I want to place here: 123 "Hello"

    foo: routine [
        /local
        x [data!]
    ]
    [
        x: _foo
        ; next line do now work
        ; push my-red-block x/a
    ]
 ]

view [button "Select" [sqlite/foo]] 

my-red-block 这里是红色block,我想用红色/系统部分的数据填充。

https://github.com/meijeru/red.specs-public/blob/master/specs.adoc#routine-type

【问题讨论】:

    标签: red red-system


    【解决方案1】:

    简介

    Red 使用数据堆栈来传递参数并返回结果。堆栈上的每个值都是一个装箱结构,大小为 4 个平台指针,并且可能包含对外部缓冲区的引用;这意味着您需要构造它们并将它们压入堆栈,尽管如果您返回它们,一些原始的 Red/System 类型(例如 logic!integer!)会自动提升。

    但是,在您的情况下,不需要使用堆栈,因为您希望直接在块中分配值。具有低级编程经验和了解Red/System 和红色runtime API 是此任务的基本先决条件。因此,让我们以您的示例为例,逐步进行。

    开箱

    1. 你有一个块,你想给它附加两个值,123"Hello"。假设您想从 Red/System 执行此操作。为此,我们需要编写一个例程。
      list: []
      foo: routine [][...]
      
    2. 在此例程中,您需要获取list 字引用的块。实现这一点的困难方法是实例化一个符号并通过其 ID 在全局上下文中查找值:

      list: []
      
      foo: routine [
          /local
              blk [red-block!]
      ][
          blk: as red-block! _context/get-global symbol/make "list"
      ]
      

      list 作为参数传递会更合理,但出于教育目的,我会保持原样。

    3. 现在我们想将123 附加到这个块。 block/rs-append 函数正是这样做的,但它接受一个装箱的参数。所以我们需要自己先给123自己加框。

      1. This 是装箱整数的样子;如您所见,它只是 32 位 123 值 + 插槽标头和填充。我们可以自己构造和初始化这样的结构:
        int: stack/push*         ; allocate slot on data stack
        int/header: TYPE_INTEGER ; set datatype
        int/value: 123           ; set value
        
        幸运的是,Red 运行时已经使用 integer/box 函数覆盖了这一点,该函数采用 Red/System integer! 并返回一个装箱的 red-integer! 结构:
        integer/box 123
        
      2. 现在我们需要将这个装箱的整数附加到一个块中。直观地,我们可以检查block.reds definitions 并找到符合我们要求的block/rs-append
        block/rs-append blk as red-value! integer/box 123
        
        在这一步结束时,我们有:
      list: []
      
      foo: routine [
          /local
              blk [red-block!]
      ][
          blk: as red-block! _context/get-global symbol/make "list"
          block/rs-append blk as red-value! integer/box 123
      ]
      
    4. 现在我们要附加一个"Hello" 字符串,但首先我们需要构造它。红色字符串支持 UTF-8 并使用固定大小的内部编码(每个字符 1、2 或 4 个字节,取决于最大代码点大小);需要手动处理很多细节,因此构造此类字符串的典型方法是从c-string! 转换它。

      list: []
      
      foo: routine [
          /local
              blk [red-block!]
              str [c-string!]
      ][
          blk: as red-block! _context/get-global symbol/make "list"
          block/rs-append blk as red-value! integer/box 123
          str: "Hello"
      ]
      

      检查string! datatype runtime definitions,你会注意到一些以load为前缀的方便包装器;这是一个约定,表明此类函数可用于从低级 Red/System 部分构造(即“加载”)高级 Red 值,在我们的例子中,red-string! 来自 c-string!。由于我们想在块的尾部构造它,我们可以使用string/load-in

      str: "Hello"
      string/load-in str length? str blk UTF-8
      

      请注意,我使用 length? 而不是 size? 来排除以 NUL 结尾的字节。

    结论

    就是这样。在一天结束的时候,我们可以稍微整理一下代码并检查它是否可以正常工作:

    Red [Note: "compile in release mode (-r flag)"]
    
    list: []
    
    foo: routine [
        /local
            blk [red-block!]
            int [integer!]
            str [c-string!]
    ][
        blk: as red-block! _context/get-global symbol/make "list"
        int: 123
        str: "Hello"
    
        block/rs-append blk as red-value! integer/box int
        string/load-in str length? str blk UTF-8
    ]
    
    foo
    probe list
    

    在发布模式下编译此脚本并从 shell 执行生成的二进制文件会给我们预期的结果:

    [123 "Hello"]
    

    毋庸置疑,这一切对于新手来说可能会让人不知所措:虽然 Red 和 Red/System 都有不错的文档和学习资源,但它们通过运行时交互的桥梁是未知领域。这样做的原因是因为项目正在发展,API 还没有稳定下来,所以,目前还不是记录它并确定设计决策的合适时机。不过,经验丰富的开发人员可以很快掌握方向,但这需要对 Red 的评估模型有扎实的概念理解——这些基础知识是您首先需要掌握的。

    还有大量的library bindings 可供您学习——从原始示例来看,您正试图在 SQLite 之上创建一个 CRUD 视图界面。

    【讨论】:

    • 非常感谢!你能补充一下为什么它应该在发布模式下编译吗?
    • @DmitryBubnenkov 参见this 文章。您当然可以使用开发模式,但是每次在您的 Red/System 代码中引入新的唯一运行时调用时,都需要重新构建 libRedRT。默认情况下,libRedRT 仅导出 pre-defined set 的运行时定义,如果您的代码使用不是来自该列表的调用,那么如果没有自定义 libRedRT,它将无法在开发模式下编译。
    • 您展示了对全局上下文的访问权限,但是如何找到放置在单独上下文中的符号?也许我应该开始新的问题?
    • @DmitryBubnenkov 因为你真的需要作为参数传递给引用该上下文的例程,例如一个词或一个物体。一旦有了符号 ID 和上下文节点,就可以使用 _context/get-any 获取值。使用全局上下文更容易,因为它的节点可以通过global-ctx 变量访问。 OTOH,在您的情况下,您应该通过块本身。
    猜你喜欢
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多