Red/Rebol 的函数如何通过值或引用传递参数?

如何解决Red/Rebol 的函数如何通过值或引用传递参数?

我对以下两个代码的结果感到困惑:

代码 1:

>> f: func [x][head insert x 1]
== func [x][head insert x 1]
>> a: [2 3]
== [2 3]
>> f a
== [1 2 3]
>> a
== [1 2 3] ;; variable a is destroyed

代码 2:

>> g: func [x y][x: x + y]
== func [x y][x: x + y]
>> c: 1 d: 2
== 2
>> g c d
== 3
>> c
== 1
>> d
== 2
;;variable c and d keep their original values

我的问题是:Red/Rebol 中的函数如何通过值或引用获取它们的参数?

解决方法

这是个好问题。答案是:参数是按值传递的,但有些参数中可能包含引用。

Rebol/Red 中的每个值都表示为大小一致的盒装结构,通常称为 slotcell。该结构在逻辑上分为 3 部分:header、payload 和 extra。

  ┌─────────┐
  │ header  │
  ├─────────┤ Historically,the size of the value slot is 4 machine pointers in size,│ payload │ 1 for header,1 for extra,and 2 for payload.
  │         │ E.g. on 32-bit systems that's 128 bits,or 16 bytes.
  ├─────────┤ 
  │ extra   │
  └─────────┘
  • 标头包含各种元信息,有助于识别有效负载包含的值,最重要的部分是类型标记,或者用 Rebol 的话说,是数据类型 ID
  • 有效载荷包含一些值的数据表示,例如数字、字符串、字符等。
  • 额外的部分用作为优化(例如缓存)和存储不适合负载的数据保留的空间。

现在,值槽具有统一的大小,自然,有些数据根本无法完全放入其中。为了解决这个问题,值槽可以包含对外部缓冲区引用(基本上是一个带有额外间接层的指针,以使数据可以垃圾回收并在多个槽之间共享)。

  ┌─────────┐
  │ header  │
  ├─────────┤
  │ payload │ --→ [buffer]
  │         │
  ├─────────┤
  │ extra   │
  └─────────┘

适合值槽的值(例如scalar!)称为直接,而不适合的值(例如series!)称为间接:因为其中的引用在值槽和实际数据之间引入了一个间接级别。例如,here 是在 Red 中定义各种插槽布局的方式。

值槽的内容只是一堆字节;运行时如何解释它们取决于标头中的数据类型 ID。一些字节可能只是文字,而其他字节可能是指向数据缓冲区的间接指针。将参数传递给函数只会复制这些字节,而不管它们的含义。因此,在这方面,文字和引用的处理方式相同。

所以,如果你有一个内部看起来像这样的值槽:

┌────────┐
│DEADBEEF│ header
├────────┤
│00000000│ payload
│FACEFEED│
├────────┤
│CAFEBABE│ extra
└────────┘

那么,比如说,FACEFEED 可以是一个有符号整数 -87097619,或者打包在一起的不同大小的位域,或者它可以是一个机器指针:这取决于标头中的数据类型 ID (例如 EF 字节)归因于它。

当值槽作为参数传递给函数时,它的所有字节都将简单地复制到计算堆栈上,无论它们编码或表示什么。对于直接值,逻辑很简单:如果在函数内修改了参数,则原始值保持不变,因为它只是一个副本。这就是您的第二个示例的全部内容。

 Parameter        Stack
┌────────┐      ┌────────┐
│DEADBEEF│      │DEADBEEF│
├────────┤      ├────────┤
│00000000│      │00000000│ Both represent the same integer -87097619.
│FACEFEED│      │FACEFEED│ ← You modify this one,with no effect on the other.
├────────┤      ├────────┤
│CAFEBABE│      │CAFEBABE│
└────────┘      └────────┘

但是对于间接值,它更有趣。它们也被逐字复制,但这会使两个副本共享对单个缓冲区的相同引用(请记住,两个插槽中表示引用的字节是相同的)。因此,当您通过一个(例如,头部的 insert 元素)修改缓冲区时,另一个也会反映更改。

 Parameter        Stack
┌────────┐      ┌────────┐
│DEADBEEF│      │DEADBEEF│
├────────┤      ├────────┤
│00000000│      │00000000│ Both refer to the same buffer (same machine pointers!)
│FACEFEED│──┐───│FACEFEED│ 
├────────┤  │   ├────────┤
│CAFEBABE│  │   │CAFEBABE│
└────────┘  │   └────────┘
            ↓
      [b u f f e r] ← You modify the content of the buffer.

回到第一个例子:

>> f: func [x][head insert x 1]
== func [x][head insert x 1]
>> a: [2 3]
== [2 3]
>> f a
== [1 2 3]
>> a
== [1 2 3] ;; variable a is destroyed

简化很多,这就是它在引擎盖下的样子:

       value slot               buffer     value slot (parameter on stack)
<word a in global context> --→ [1 2 3] ←-- <word x in function's context>

当然,有多种方法可以克隆值槽一个它所引用的缓冲区:这就是 copy 所做的。

>> f: func [x][head insert x 1]
== func [x][head insert x 1]
>> a: [2 3]
== [2 3]
>> f copy a
== [1 2 3]
>> a
== [2 3]

图解(再次简化):

value slot          buffer
     <x>     --→   [1 2 3]
     <a>     --→   [2 3]

系列值(例如块)在其有效负载中还包含另一条数据:索引。

>> at [a b c d] 3 ; index 3,buffer → [a b c d]
== [c d]

当将块作为参数传递时,它的索引也会被复制,但与数据缓冲区不同的是,它不会在两个值槽之间共享。

 Parameter        Stack
┌────────┐      ┌────────┐
│DEADBEEF│      │DEADBEEF│
├────────┤      ├────────┤
│00000000│      │00000000│ Suppose that 0's here are an index.
│FACEFEED│──┐───│FACEFEED│ Modifying this one won't affect the other.
├────────┤  │   ├────────┤
│CAFEBABE│  │   │CAFEBABE│
└────────┘  │   └────────┘
            ↓
      [b u f f e r]

所以:

>> foo: func [x][x: tail x] ; tail puts index,well,at the tail
== func [x][x: tail x]
>> y: [a b c]
== [a b c]
>> foo y
== [] ; x is modified
>> y
== [a b c] ; y stays the same

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res