2

我需要将我在 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

4

1 回答 1

3

介绍

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

但是,在您的情况下,不需要使用堆栈,因为您想直接在块中分配值。具有低级编程经验和使用 Red运行时 API的Red/System知识是完成此任务的基本先决条件。因此,让我们以您的示例并逐步进行操作。

开箱

  1. 你有一个块,你想向它附加两个值,123并且"Hello". 假设您想从 Red/System 执行此操作。为此,我们需要编写一个例程。
    list: []
    foo: routine [][...]
    
  2. 在此例程中,您需要获取listword 引用的块。很难做到这一点的方法是实例化一个符号并通过其 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. 就是装箱整数的样子;如您所见,它只是 32 位123值 + 插槽标头和填充。我们可以自己构造和初始化这样的结构:
      int: stack/push*         ; allocate slot on data stack
      int/header: TYPE_INTEGER ; set datatype
      int/value: 123           ; set value
      
      幸运的是,Red 运行时已经使用带有 Red/System并返回盒装结构 integer/box的函数来 覆盖它:integer!red-integer!
      integer/box 123
      
    2. 现在我们需要将这个装箱的整数附加到一个块中。直观地说,我们可以检查block.reds定义并找到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!数据类型运行时定义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 的评估模型有扎实的概念理解——这些基础知识是您首先需要掌握的。

您还可以学习大量的库绑定——从原始示例来看,您正在尝试在 SQLite 之上创建一个 CRUD 视图界面。

于 2020-06-16T15:39:26.473 回答