![`\let\A\B` 和 `\let\A=\B` 之间有什么区别吗?](https://linux22.com/image/429664/%60%5Clet%5CA%5CB%60%20%E5%92%8C%20%60%5Clet%5CA%3D%5CB%60%20%E4%B9%8B%E9%97%B4%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%E5%90%97%EF%BC%9F.png)
我见过有人写这样的东西
\let\original@somemacro=\somemacro
虽然我通常写
\let\original@somemacro\somemacro
它们之间有什么区别吗?
(我相信这个问题肯定是在本网站的其他地方提出来的,但我找不到它。)
答案1
由于您事先知道组件的值,因此您可以非常安全地显式地执行操作,但是在代码(即宏)中,您可能不知道用户可能希望分配什么,如果您不使用作为=
分配的一部分,您可能会陷入困境。因此,使用它是个好习惯。
考虑一下这种情况,=
在分配中如果没有出现错误\let
:
\documentclass{article}
\begin{document}
\def\doit#1{\let\X#1}
\doit{=} what?
\X oops
\end{document}
=
将其与将 添加到语法时的输出进行比较\let
。啊,这比预期的要多得多:
\documentclass{article}
\begin{document}
\def\doit#1{\let\X=#1}
\doit{=} what?
\X much better
\end{document}
以下还有另一个案例来强调差异:
\documentclass{article}
\begin{document}
\def\deftok#1#2{\let#1= #2\empty}
\deftok\W{ }
*\W* success
\def\deftok#1#2{\let#1=#2\empty}
\deftok\W{ }
*\W* fail
\def\deftok#1#2{\let#1 #2\empty}
\deftok\W{ }
*\W* fail
\end{document}
在此示例中,如果您希望对空格进行赋值,则不仅是=
命令式, 后面的空格也是命令式。语法还允许对 进行赋值。=
\deftok\W{}
\empty
\W
因此,总而言之,空格和=
标记可能会成为有问题的分配,\let
必须小心谨慎。我在我的tokcycle
软件包 V1.1 中艰难地学到了这个教训。“一朝被坑,二朝被学!”
答案2
前面的答案说明了为什么=
在语法中使用它很有用\let
。另一个论点是“更清晰”。
=
我展示了不同的观点,即在语法中使用 有点不切实际的情况\let
:当 的第二个标记\let
由 构造时\csname...\endcsname
。以下示例是错误的:
\let\foo = \csname bar\endcsname
因为\let
扫描其参数时没有扩展:上面的示例确实如此\let\foo=\csname
,并且在处理bar\endcsname
时会出现错误。因此,我们必须使用链:\endcsname
\expandafter
\expandafter\let \expandafter\foo \expandafter=\csname bar\endcsname
\expandafter
如果这里用不到的话,可以省掉一个=
:
\expandafter\let \expandafter\foo \csname bar\endcsame
如果扫描的两个标记都\let
必须成对构造,\csname...\endcsname
那么我们可以使用另一个技巧,即“\expandafter
从对内开始\csname...\endcsname
”:
\expandafter\let \csname foo\expandafter\endcsname \csname bar\endcsname
在旧宏中,宏主体中不使用=
from语法,因为它会在 TeX 内存中节省一个标记。但这在今天已无关紧要。\let