它是否\let
真的创建了一个新的控制序列,还是仅仅将一个指针分配给已经定义的控制序列?
Knuth 说道:
let\cs=<token>
给出\cs
标记的当前含义。如果<token>
是另一个控制序列,\cs
将获得与该控制序列相同的意义。(TeXbook 206)
假设我定义了一个新的列表环境bars
,其中\bar
只是的另一个名称\item
:
\newenvironment{bars}
{\begin{enumerate}\let\bar\item}
{\end{enumerate}}
然后在我的文档中使用该环境 1000 次,如下所示:
\begin{bars}
\bar bla bla
\bar bla bla bla
\end{bars}
内存中有多少个位置最终具有与\item
我编译文档时相同的内容?1、2 还是 1001?
答案1
您的问题的答案是“再来一个”,即\item
和\bar
(因此,总共两个)。
该方法\let\a<token>
的工作原理是将 的含义逐字复制<token>
到控制序列 中\a
,这样每当\a
被“执行”时,它的行为就和 一样<token>
。此复制是在指令执行时完成的\let
,因此无论 被使用多少次\a
,都不会产生新的变化;此外,如果<token>
更改它是意思(比如,通过另一个\let
),的意思\a
不受影响。
你对“指针”一词的使用在某种意义上是不恰当的,因为 TeX 作为一种语言没有内存模型,并且(必然)它所实现的语言也不能随机访问它是内存模型,其实现的内部细节也与理解其操作无关。然而,即使假设 TeX 是用(比如说)C 实现的,指向 token 的指针的类似物也是
\def\a{<token>}
假设 是有效的 C 语法,则其结果类似于*\a = <token>
。虚语法*\a = *<token>
对应于\let\a<token>
,而语法*\a = <token>
,虽然与第一个语法类似,但实际上会这样\a
定义:\def\a{<other token>}
重新定义 <token>
,这在 TeX 中是不可能的。因此 TeX 中并没有与指针完全类似的对象。
答案2
尽管 TeX 可以存储给定宏的多个版本(局部于 { } 组),但通常很难填满内存,因为一旦离开组,内存就会被回收并重新使用(这是我最初评论的基础)。大多数环境(如 itemize)都包含此类分组。当现有命令被 \def'd 或 \let'd 为组内的其他内容时,旧版本将被保存(堆叠)并在组末尾恢复。
除非您管理嵌套组或类似物的无限递归,否则任何标准构造都不会产生太多的“堆栈”浪费。
可以生成大量具有给定宏的不同定义的嵌套组,但你必须有点狡猾:
\documentclass[a5paper,12pt]{article}
\usepackage[margin=20mm]{geometry}
%% version of plain TeX \loop that uses global macros
\def\gloop#1\repeat{\gdef\body{#1}\giterate}
\def\giterate{\body \global\let\next\giterate \else\global\let\next\relax\fi \next}
\let\repeat=\fi % this makes \loop...\if...\repeat skippable
\begin{document}
\raggedright
\section*{Ascending}
\newcount\n
\global\n=0
\gloop
\ifnum \n<100
\bgroup
\edef\foo{\the\n}
\let\baz=\foo
\global\let\foobar=\baz
$\foo^{\baz}_{\foobar} \uparrow$
\global\advance\n 1
\repeat
\section*{Descending}
\global\n=0
\gloop
\ifnum \n<100
$\foo^{\baz}_{\foobar} \downarrow$
\egroup
\global\advance\n 1
\repeat
\end{document}