作者归档:隋辨

新年随笔 (2022)

今天是2022年第一天,准确说是公元2022年。基督教胜利了,不然怎么大多数国家会这样计时:耶稣诞生 130周年,耶诞 1800年……公元2022周年?人们跨越这样的时间点,如同踏上一片新大陆。我现在边敲字,边听歌,女朋友在看书,穿着跟圣诞老人一样红的毛衣,旁边是她送给我我的向日葵——这是我第一次收到花。

曾经听说,男人一辈子只会收到一次花,就是在他的葬礼上。——我太幸运了。是的,今年我做了不少事情,年初,给一群网友直播《机器学习》的课程,但因为还有学业,上到“深度学习”部分就结束了,有些遗憾。下半年找到一份实习,窥探一下行业,理解学校和工业界之间的差距。和女朋友在一起——学习走进一个人的内心。现在我发觉,那些焦虑、担忧和辗转反侧值得,但如果说我努力并不会成功呢,我想我还是会做下去。

和疫情影响的那些人相比,我这样的学生很幸运,不需要花两个小时车程去上班,不用照顾孩子,不必在三十岁去考研。看见那些残忍的新闻,我总想,我得到的都是侥幸,失去的都是人生啊。想要更积极一些,担得起前路的风雨。前几年都没什么新年愿望,我想今年是有必要了,许下愿望,以终为始,即便达不到目标,年末时候好歹也发现自己曾努力过。

每天看书,起码两页。去年看得太少以至不愿意分享出来,可惜。未来几个月,要写论文,要找工作,也许很忙,但看书不能停下,哪怕是看手机屏幕大小的两页书。上学的时候尚且忙,不去读书,工作之后哪还会有更多心思去读呢?实习告诉我们,人只要工作起来,休息时就想娱乐,没有毅力脑子一点不想动,更何况是做脑力工作。

多睡点觉,起码达到每天七个半小时。去年我睡得太少,太不规律,影响身体健康。身体是革命的本钱,现在睡不好,以后怎么能安心劳作?

作为年更作者,我也得多更新一点博客,为自己多输出,总结经验,巩固记忆和表达。

你也可以写下新年愿望,清晰且容易实践,这样我们明年跨年,不也能再回首望望不是?祝你新年快乐!

MLBiNet:跨句的语义信息提取

MLBiNet: A Cross-Sentence Collective Event Detection Network

zjunlp/DocED: Source code for the ACL 2021 paper "MLBiNet: A Cross-Sentence Collective Event Detection Network ".

跨句子问题的解决关键在于:编码语义信息,在文档级去建模事件的相互依赖关系。具体地说,我们首先设计了一个双向解码器,在解码事件标记向量序列时,模拟一个句子内的事件相互依赖关系。其次,利用信息聚合模块对句子级语义信息和事件标签信息进行聚合。最后,我们将多个双向译码器堆叠起来,并提供跨句信息,形成多层双向标签结构,实现信息在句子间的迭代传播。

Seq2Seq 多层双向网络 捕捉多个不同事件。四个部分:语义编码器、双向解码器、信息聚合模块、堆叠式多元双向标记层

用 attention-RNN 作为主要的架构

a) 独立的编码器模块在融合句子级和文档级语义信息方面具有灵活性;

b) RNN解码器模型的上下文向量和当前状态的学习捕捉:可以捕获序列事件标签相关性,将预测的标签向量作为预测 t 符号的输入

事件抽取和一般 RNN 的区别

事件抽取中生成序列长度是已知的,与原始序列一致。

ED任务解码器的词汇表不是单词,而是事件类型的集合

语义编码器

对 word 和 NER type 分别做 embedding,将两个信息拼接起来,每个 token 有了可理解的表征 \mathbf e_t

用 Skip-gram 预训练 word。在训练过程中对NER型嵌入矩阵进行随机初始化和更新。

利用双向LSTM和自注意机制对每个标记的句子级上下文信息进行编码,也就是每次按句子训练。

word embedding + NER type embedding -> e_t

LSTM + self-attn ->h_t^a

对于每个 word:

\mathbf x_t = [\mathbf h_t^a; \mathbf e_t]

相当于是 skip-connection

双向解码器

事件抽取中生成序列长度是已知的,与原始序列一致。用双向编码器,模拟句子间的关系。

前向解码

\begin{gathered}
\overrightarrow{\mathbf{s}}_{t}=f_{\mathrm{fw}}\left(\overrightarrow{\mathbf{y}}_{t-1}, \overrightarrow{\mathbf{s}}_{t-1}, \mathbf{x}_{t}\right) \\
\overrightarrow{\mathbf{y}}_{t}=\tilde{f}\left(W_{y} \overrightarrow{\mathbf{s}}_{t}+b_{y}\right)
\end{gathered}

后向解码

\begin{gathered}
\overleftarrow{\mathrm{s}}_{t}=f_{\mathrm{bw}}\left(\overleftarrow{\mathbf{y}}_{t+1}, \overleftarrow{\mathrm{s}}_{t+1}, \mathrm{x}_{t}\right) \\
\overleftarrow{\mathbf{y}}_{t}=\tilde{f}\left(W_{y} \overleftarrow{\mathrm{s}}_{t}+b_{y}\right)
\end{gathered}

双向解码

双向解码器通过组合 forward 和 backward 解码器立即模拟事件相互依赖性。垂直标记层利用了两个向前的参数和标签注意机制来捕获双向的事件依赖。

信息聚合

对于当前句子,我们关注的信息可以总结为记录哪些实体和令牌触发哪些事件。因此,为了总结信息,我们使用事件标签向量 \mathbf y_t 作为输入,设计与事件标签向量 \mathbf y_t 的LSTM层(图1中所示的信息聚合模型)。

\tilde{\mathbf{I}}_{t}=\overrightarrow{\operatorname{LSTM}}\left(\tilde{\mathbf{I}}_{t-1}, \mathbf{y}_{t}\right)

最后的向量 \tilde{\mathbf I}_{ni} 作为总结向量。

句子级的信息聚合模块架起了跨句信息的桥梁,形式化的信息很容易集成到其他句子的解码过程中,增强了事件相关信息。

多层双向网络

在该模块中,我们将多个双向标记层堆叠机制,以在双向解码器中聚集相邻句子的信息,并在句子中传播信息。由双向解码器层和信息聚合模块录制的信息 (\{\mathbf y_t \}, \mathbf I_i) 已捕获句子中的事件相关信息。但是,跨句子信息尚未互动。对于给定的句子,正如我们在表1中所看到的那样,其相关信息主要存储在邻近的句子中,而遥远的句子很少相关。因此,我们建议在相邻句子中传输总结句子信息 \mathbf I_i

由双向解码器层和信息聚合模块录制的信息 (\{\mathbf y_t \}, \mathbf I_i) 捕获句子中的事件相关信息。但是,跨句子信息尚未获取。

可以通过将输入扩展为\mathbf I_{i-1}\mathbf I_{i+1} 来形成跨句子信息。 k 是层数。

\begin{gathered}
\overrightarrow{\mathbf{s}}_{t}=f_{\mathrm{fw}}\left(\overrightarrow{\mathbf{y}}_{t-1}^{k}, \overrightarrow{\mathbf{s}}_{t-1}, \mathbf{x}_{t}, \mathbf{I}_{i-1}^{k-1}, \mathbf{I}_{i+1}^{k-1}\right) \\
\overleftarrow{\mathbf{s}}_{t}=f_{\mathrm{bw}}\left(\overleftarrow{\mathbf{y}}_{t+1}, \overleftarrow{\mathbf{s}}_{t+1}, \mathbf{x}_{t}, \mathbf{I}_{i-1}^{k-1}, \mathbf{I}_{i+1}^{k-1}\right) \\
\overrightarrow{\mathbf{y}}_{t}^{k}=\tilde{f}\left(W_{y} \overrightarrow{\mathbf{s}}_{t}+b_{y}\right) \\
\overleftarrow{\mathbf{y}}_{t}^{k}=\tilde{f}\left(W_{y} \overleftarrow{\mathbf{s}}_{t}+b_{y}\right) \\
\mathbf{y}_{t}^{k}=\left[\overrightarrow{\mathbf{y}}_{t}^{k} ; \overleftarrow{\mathbf{y}}_{t}^{k}\right]
\end{gathered}

凯文 · 凯利的 69 岁人生建议

凯文· 凯利被人称为“互联网教父”。他的博客,有很多对年轻人的建议。我翻译了他今年生日时的建议,就不赘述了,下面是原文。有兴趣也可以点击“阅读原文”,去他博客看看。

我又过了一个生日,不请自来又想提出一些建议:

  1. 小时候让你显得古怪的玩意,可能在你长大后会让你变得很棒 —— 如果你还没有失去它。
  2. 如果你有点困惑于能否一次带走所有东西,得了吧,最好分两次拿走。
  3. 你通过实现目标得到了什么并不重要,重要的是你通过实现目标成为了什么。在你的葬礼上,人们不会记得你做了什么,只会记得你给他们的感觉。
  4. 成功的秘诀:少承诺、多兑现。(少说多做)
  5. 有借口的道歉算不上道歉,有请求的赞美也算不上赞美。
  6. 耶稣、超人和特蕾莎修女从未创造过艺术。只有不完美的人才能创造艺术,因为艺术源于残缺。
  7. 传销的人往往会试图说服你“那不是传销”。
  8. 学习如何打“称人结”。在黑暗中练习。用一只手练习。往后余生,你用这个结的次数会超乎想象。(这样的结一般用于攀岩、消防以及各种各样的场景)
  9. 如果一件事在你认为它会失败的地方失败了,那就不是失败。
  10. 别受制于紧急的事情,做重要的事。
  11. 如果门之前是开着的,就让它开着;如果门之前是关着的,就让它关着。
  12. 最大的回报来自于做一些尚未有人命名的事。如果可能的话,去做话语无法描述的工作。
  13. 阳台或门廊至少要有 2 米深,否则无法使用。
  14. 别为了赚钱而创造,要为了创造而存钱。对好工作的奖励是更多的工作。
  15. 除了爱情,所有的事情都从退出策略开始。准备好结局吧。几乎任何事情进去都比出去容易。
  16. 对员工进行足够好的培训,让他们能够找到另一份工作,但对他们足够好,让他们永远不想找到另一份工作。
  17. 不要试图让别人喜欢你,试图让他们尊敬你。
  18. 成熟的基础是,那虽然不是你的错,但并不意味着不是你的责任。
  19. 想出一个好主意需要大量的坏主意。
  20. 智慧意味着有更多的问题而不是答案。
  21. 在背后夸赞别人——它会以另一种形式回到你身边。
  22. 大多数一夜之间的成功——事实上任何重大的成功——都需要至少 5 年的时间。合理安排你的生活。
  23. 只要能转变自己的思维,你就可以永远保持年轻。
  24. 任何人以任何理由询问你的账户信息,都要假设他们在诈骗,除非他们能证明清白。证明的方法是给他们回电话,或者用你的而非他们提供的号码或网站来登录你的账户。当他们通过电话、信息或电子邮件联系你时,不要泄露任何身份信息。你必须控制通信渠道。
  25. 持续的愤怒会让你变蠢。
  26. 严于律己,宽于待人。反过来对每个人来说都是灾难。
  27. 要回应别人的侮辱,最好的回答是“你可能是对的”。因为他们通常是对的。
  28. 历史上最邪恶的事,总是由那些真正相信自己在与邪恶斗争的人做的。小心与邪恶斗争。
  29. 如果你能避免寻求别人的认同,你的力量就是无限的。
  30. 当一个孩子没完没了地问“为什么”,最聪明的回答是:“我不知道,你是怎么想的?”
  31. 要想成为富有的人,就应该积累所有金钱买不到的东西。
  32. 成为你想希望看见的那种改变。
  33. 当头脑风暴、即兴创作、与人合奏时,如果你都能愉快地表示“是的……,而且……”,而不是一个令人泄气的“不……,但是……”,你会走得更远、更深入。
  34. 工作为了“成为”,而不是为了“得到”。
  35. 不要借钱给朋友,除非你要把钱当礼物。
  36. 在通往伟大目标的路上,要像所有的胜利都是最终目标一样,去庆祝每一个微小胜利。无论你前进多远,你都是胜利者。
  37. 冷静是会传染的。
  38. 即使是愚蠢的人,在大多数事情上也可能是正确的。大多数传统观点都是正确的。
  39. 切东西别冲着自己。
  40. 给我看看你的日程表,我会告诉你你的优先事项。告诉我你的朋友是谁,我就知道你将去往何方。
  41. 搭便车的时候,你要看起来像你自己愿意载的人。
  42. 思考他人弱点容易,审视自己弱点很难,但回报更高。
  43. 值得重复的是:三思而后行。(注,木匠有条规矩,度量两次才动手)
  44. 你对生活的热情应该完全适合你,但人生目标应该超越你。要为比你自己伟大的目标而工作。
  45. 如果你不知道自己最需要什么,那可能就是睡眠。
  46. 当玩大富翁时,花你所有的钱来购买、交换或交易橙色产权。不要为公共设施操心。(注,橙色局级空间代表某些当地的公用事业,如城市供水、供气、供热、公共交通、污水处理、垃圾处理等行业,代表特许经营权。公共基础设施如电、煤气、铁路等)
  47. 如果你借了东西,归还时试着把它变得比你收到时还好——清洗,磨尖,加满油。
  48. 即使在热带地区,晚上也比你想象的要冷,记得带上暖和的行李。
  49. 要让人群或醉汉安静,只需低声耳语。
  50. 每天写下一件你感激的事情是最便宜的心理治疗方法。
  51. 有人告诉你某事是错的,他们通常是对的。有人告诉你如何解决这个错误,他们通常是错的。
  52. 如果你看见了一只蟑螂,那说明还有很多只你没看见。
  53. 钱的作用被高估了。真正的创新很少需要大量的钱。如果是这样,亿万富翁就会垄断新发明,但他们没有。相反,几乎所有的突破都是由那些缺钱的人取得的,因为他们被迫依靠自己的激情、毅力和才智来找到新方法。贫穷是创新的优势。
  54. 忽略别人可能会对你持有什么看法,因为他们根本没想过你。
  55. 避免按闹钟延迟按钮。那只是训练你睡过头。
  56. 永远只说必要的话。(言多必失)
  57. 你生命的礼物是——为了发现你的天赋是什么。当你弄清楚你的使命是什么时,你会完成你的使命。这不是悖论,这是真理。
  58. 对待别人的态度,不取决于他们有多坏,而应该只依赖于你自己有多好。
  59. 通过改变行为来改变思维方式,比通过改变思维方式来改变行为要容易得多。把你所寻求的改变付诸行动。
  60. 如果你想吃任何甜点,只需要规定自己只吃三口就好。
  61. 为你接触的每个人带来祝福,当你需要帮助时,他们自会很高兴帮你解决问题。
  62. 坏事发生得很快,但几乎所有好事都是慢慢发生的。
  63. 不要担心如何开始或从哪里开始。只要你不断前进,你就会比开始时更成功。
  64. 当你遇到卡住的螺栓或螺丝时:右紧左松。
  65. 如果你遇到一个混蛋,忽略他。如果你每天都遇到混蛋,就得审视自己了。
  66. 跳舞的时候,把臀部用起来。
  67. 我们不是暂时拥有灵魂的肉体。我们是暂时拥有肉体的灵魂。
  68. 如果你懊恼于别人的愚蠢信念,并且想减轻这种感觉,只要想办法理解他们为什么这样想就好了。
  69. 如果你的目标没有时间表,那它就是一个梦。
  70. 生活中所有最大的收获——在财富、关系或知识方面,都来自于复利的魔力,它将微小的、稳定的收益放大。你所需要的就是经常增加 1%,而不是减少 1%。
  71. 人们往往错过最伟大的突破,因为它们看起来很辛苦。
  72. 听演讲时,人能记住的观点不会超过三个。
  73. 我敬佩的每一个人,无一例外读的书都比我多。
  74. 最好的老师叫做“行动”。
  75. 玩有限游戏是为了输赢,玩无限游戏是为了让游戏继续。寻找无限的游戏,因为它们能提供无限的奖励。
  76. 凡事总是先难后易。——在突破出现之前,它都是一个愚蠢的想法。
  77. 用钱能解决的问题不是真正的问题。
  78. 当你被困住的时候,睡一觉。让潜意识为你解决问题。
  79. 你的工作是无止境的,但你的时间是有限的。 你不能限制工作,所以你必须限制你的时间。 时间是你唯一可以管理的事情。
  80. 要成功,先让别人给你报酬;要变富,就要帮助别人成功。
  81. 孩子们完全接受甚至会渴望家庭规则。在我们的家庭中,“我们有一个关于XX的规则”,这是父母制定家庭规范的唯一理由。事实上,“我有一个规则”,其实是你为自己设定规范所需要的唯一理由。
  82. 所有的枪都上了膛。
  83. 很多退步都来自止步不前。
  84. 这是创造的最佳时机。20年后,那些最伟大、最酷的发明没有一个被发明出来。你还没有迟到。
  85. 没有风雨,不见彩虹。
  86. 你遇到的每一个人,都对你几乎一无所知的一些事情了如指掌。你的工作是发现它是什么,而它不会是显而易见的。
  87. 和你结婚的不是一个人,而是一个家庭。
  88. 永远称赞别人,承担责任。
  89. 凡事要节俭,惟有热情要放纵。
  90. 创造时,总要有一些备用,额外的材料,额外的零件,额外的空间,额外的装饰。这些额外的东西可以作为容错,减轻压力,为未来积蓄资源——它们是最便宜的保险。
  91. 有些东西不需要完美就可以很好。特别是婚礼。
  92. 不要让你的收件箱成为你的待办清单。
  93. 解开乱麻的最好方法不是解开结,而是把绳圈拉得越来越宽。只要把混乱弄得尽可能大,尽可能松,尽可能打开就行了。当你放松这些结时,它们会自己解开。在电线、绳子、软管、纱线,或电缆上都有效。
  94. 做个好祖宗。做一些会让后代感激的事情——一件简单的事是种树。
  95. 想打败对手,先成为他们的朋友。
  96. 把一件简单的事情——几乎任何事情——看得极其严肃认真,就好像它是世界上唯一的事情,或者就像整个世界都在它里面,认真对待它,你就能照亮天空。
  97. 历史告诉我们,从现在起 100 年后,你相信的一些假设将被证明是错误的。今天你应该问自己一个很好的问题:我有哪些地方做错了?
  98. 对你的孩子好点,因为他们会选择你的养老院。
  99. 像这样的建议不是法律。它们就像帽子。如果一个不合适,就试试另一个。

我发现翻译其实是一种学习方法。也许原因在语言转换过程中:一是重复次数多,二是翻译时应用知识的过程,充斥着反刍。一来二去,遇事居然可以唤醒相应的句子,实在不错。

使用 VScode 远程 ssh 连接

服务器安装 ssh

以 Ubuntu 为例,通过使用Ctrl+Alt+T键盘快捷键或单击终端图标打开终端,然后openssh-server通过键入以下命令安装软件包:

sudo apt update
sudo apt install openssh-server

安装完成后,SSH服务将自动启动。要验证安装是否成功并且SSH服务正在运行,请键入以下命令,该命令将显示SSH服务器状态:

sudo systemctl status ssh

Ubuntu附带了一个名为 UFW 的防火墙配置工具。如果系统上启用了防火墙,请确保打开SSH端口:

sudo ufw allow ssh

username使用实际用户名和ip_address安装SSH的Ubuntu计算机的IP地址更改。

如果您不知道IP地址:

ip a

修改 ssh 配置,在目录 /etc/ssh/sshd_config

PermitRootLogin yes
PubkeyAuthentication yes
AuthorizedKeysFile  .ssh/authorized_keys
PasswordAuthentication no
ChallengeResponseAuthentication no

什么意思看英文就知道了。具体查看 OpenSSH服务嚣的配置和使用 – APWABC,如下:

PasswordAuthentication密码验证关闭,并同时关闭ChallengeResponseAuthentication键盘交互方式

#PasswordAuthentication yes
PasswordAuthentication no

#ChallengeResponseAuthentication no
ChallengeResponseAuthentication no

通过PubkeyAuthentication开启密钥验证

#PubkeyAuthentication yes
PubkeyAuthentication yes

由于想要无密码登录,我们需要生成公钥和私钥,把 id_rsa.pub 改成 ~/.ssh/authorized_keys (若没有该目录,请执行mkdir ~/.ssh创建)

sudo service ssh start

客户端使用 vscode 连接 ssh

vscode 需要安装 Remote SSH 等。

vscode 编辑 settings.json,添加"remote.SSH.showLoginTerminal": true

然后点击远程资源管理器,新建连接并且

ssh username@ip_address

就大功告成了。

在Ubuntu上禁用SSH

如果出于某种原因要在Ubuntu计算机上禁用SSH,则可以通过运行以下命令停止SSH服务:

sudo systemctl stop ssh

要再次启动它,请运行:

sudo systemctl start ssh

要禁用SSH服务在系统引导运行期间启动:

sudo systemctl disable ssh

要再次启用它,请输入:

sudo systemctl enable ssh

参考链接

VSCode远程编辑,Remote-SSH,Remote Development – 亱_風 – 博客园

ubuntu 安装ssh – SegmentFault 思否

偏差和方差

偏差和方差是训练机器学习模型时需要调整的核心参数。

TL:DR

简单来说是:

误差 error = 方差 variance + 偏差 bias

偏差是通过学习拟合出来模型的期望,与真实规律之间的差距。

方差是模型每一次输出结果与模型输出期望之间的误差,即模型的稳定性。

详解

偏差

比如现在有一些学生的二维数据,身高和体重。这些数据满足 f 分布。f 是一个多项式的函数。

我们用一根直线去拟合数据(最小二乘法),偏差会很大,因为真实的是多项式的,我们的直线预测出的结果可能跟真实情况有出入。

如果我们用多项式函数去拟合数据,偏差就会很小,因为模型变得更加复杂了。

偏差是通过学习拟合出来的结果的期望,与真实规律之间的差距。即:

\mathrm {Bias}(X) = E(\hat{f}(x)) - f(x)

img

方差

若我们用多项式拟合,就会有一个问题:数据是存在噪音的,而噪音更容易影响复杂模型。带噪数据训练的直线模型,和无噪音的数据训练的直线模型是差不多的,很稳定,而在同样的情况下,多项式模型就容易受影响。

img

方差是模型每一次输出结果与模型输出期望之间的误差,即模型的稳定性:

\mathrm {Variance}(X) = E[(\hat f(X) - E[\hat f(X)])^2]

If Bias vs Variance was the act of reading, it could be like Skimming a Text vs Memorizing a Text

如果偏差 vs 方差是阅读的行为,它可能就像略读文本 vs 记忆文本

欠拟合与过拟合

简单的模型一般偏差很高,是欠拟合 (unfitting) 的,为了减少偏差,就要增加模型复杂度,增加参数或减少减少正则化。

复杂的模型一般方差较高,是过拟合的 (overfitting) ,为了降低方差,就要减少复杂度,一般用正则化方法或者换简单模型,还可以增加数据量。

在机器学习中我们要选择恰当的模型复杂度。

参考:

https://www.zhihu.com/question/27068705/answer/1689740820

https://liam.page/2017/03/25/bias-variance-tradeoff/

http://scott.fortmann-roe.com/docs/BiasVariance.html

不要再讨论值传递和引用传递了

网上有太多这样的无效讨论了,像「Java 是值传递还是引用传递?」,「Python 传可变对象就是引用传递,传不可变对象就是值传递!」、「一切都是值传递!」的话题真的是起码一个月来一次。

什么是值传递和引用传递?

传引用调用、传值调用是计算机科学里面的求值策略。求值策略定义何时和以何种次序求值给函数的实际参数,什么时候把它们代换入函数,和代换以何种形式发生。

  • 值传递意味着传 作为参数。
  • 引用传递意味着传 变量 作为参数。

注意这里的引用传递,它和引用类型毫无关系,更和 Java 和 Python 的引用类型没有关系( Java 之类的引用类型更像是 C/C++ 里面的指针)。C++ 里面的类似别名一样的引用类型,和 Java 、Python 的引用类型不同,它有时候在传递过程中符合引用调用的特点。

函数调用

要清楚为什么,就得先明白是什么。

以 C++ 为例:

void func(int x){
    x++;
}

int main(){
    int test = 2;
    func(test);
    return 0;
}
  • func 是我们调用的函数。
  • test 是一个变量,同时是 func 的实际参数 ( argument )。
  • x 也是变量,而且是局部变量,同时是 func 的形式参数 ( parameter )。
  • 实际参数是,它可以由字面量值或者变量提供。
  • 形式参数是变量,它只能是变量。
  • main 是调用者 ( caller )。
  • func 是被调用者 ( callee )。

传值调用 Call by value

值传递策略中,一旦开始函数调用过程,形式参数就会以实际参数的值初始化,且二者互不影响

相当于我有一份 doc 文档,复制了一份给你。你怎么修改你那一份,对我的文档都不会有影响。

如果是值传递,第一段代码相当于:

int test = 2;
int x = test;
x++;

C 语言是传值调用的。

传引用调用 Call by reference

引用传递策略中,函数调用将形式参数就是实际参数的别名,二者是同一个变量

相当于我有一份 doc 文档,你修改这份文档,对我来说是可见的。

如果是引用传递,第一段代码相当于:

int test = 2;
test++;

传共享对象调用 Call by sharing

传值、传引用已经不适用于现代编程语言,现在编程语言一般是传入一个特殊的引用类型,相当实际参数复制了一份地址给形式参数,但我们可以根据这个地址去修改对象,使得该函数之外的作为实际参数的变量也会发生改变。

1974 年,Barbara Liskov 意识到自己的 CLU 语言不是二者的任一种,于是命名了传共享对象调用。Python、Java、JavaScript、Scheme、OCaml 等语言都使用了传共享对象调用。(Evaluation strategy – Wikiwand

传共享对象调用中,函数传递的是一个可以共享的对象,这样就可以达到引用调用的效果:一旦被调用者修改了对象,调用者就可以看到变化。

如果坚持要一分为二,那么现在的 Java、Python 都是传值调用,只不过传的是一个可以被函数改变的对象。例如 Python:

def func(alist):
    alist.append(1)
    alist = [0]

def main():
    src = []
    func(src)
    print(src)

if __name__ == '__main__':
    main()

上面代码会打印出 [1],因为列表是可变对象,append 方法改变了 alist。而赋值局部变量的 alist = [0]对函数调用之外的作用域没有影响。

像 Java 也是这样:

class Test {
    public void addBrand(String[] book) {
        book[0] = "0";
        book = new String[]{"1"};
    }

    public static void main(String[] args) {
        Test test = new Test();
        String[] sci_book = new String[1];
        test.addBrand(sci_book);
        out.println(Arrays.toString(sci_book));
    }
}

打印出 [0] 而非 [1]

在这类语言中赋值是给变量绑定一个新对象,而不是改变对象。

等我考完试接着写!