我最近在 LaTeX2e 源中偶然发现了\protected@edef
这一点。有人能给我一个最小或简单的例子吗?我知道这与脆弱的命令/稳健性有关,但我正在寻找一个具体的例子。
答案1
Joseph 给出了很好的解释。下面给出一个完整的小例子,仅供测试以查看差异:
\documentclass{article}
\newcommand*{\firstsection}{\protect\centering First section}
\begin{document}
\edef\currentsection{\firstsection}
\section{\currentsection}
\end{document}
这编译失败。我们得到了Undefined control sequence.
因为\edef
已经丢弃了\protect
。
\documentclass{article}
\newcommand*{\firstsection}{\protect\centering First section}
\begin{document}
\makeatletter
\protected@edef\currentsection{\firstsection}
\makeatother
\section{\currentsection}
\end{document}
这可以编译并按预期工作,因为保留了宏内\protected@edef
的效果。\protect
答案2
你可能已经猜到了,\protected@edef
这是一个 TeX\edef
原语的包装器。要理解发生了什么,你需要理解脆弱命令和强大命令之间的区别:由于之前已经在这里讨论过了,所以我假设您已经了解了其中的区别!
您可能知道,对于脆弱的命令,通常需要\protect
在它们前面添加。当您使用可选参数定义宏时,使用\DeclareRobustCommand
将自动设置包含此参数的内部宏。
我将以宏为例\cite
,它接受一个可选参数,并使用 进行定义\DeclareRobustCommand
。如果你这样做
\show\cite
结果是
> \cite=macro:
->\protect \cite .
现在,该\protect
机制在简单的 中不起作用\edef
。尝试
\edef\test{\cite{stuff}}
和article
班级一起,你会得到相当神秘的
! Use of \\deftranslation doesn't match its definition.
\@ifnextchar ... \reserved@d =#1\def \reserved@a {
#2}\def \reserved@b
当然,您不会直接这样做,但可以想象一些用户输入被传递给需要\edef
材质的内部宏。那么,您如何做到同时\edef
仍允许\cite
出现在输入中?这就是\protected@edef
发挥作用的地方:
\makeatletter
\protected@edef\test{\cite{stuff}}
\show\test
给出了更合理的
> \test=macro:
->\protect \cite {stuff}.
多次\protected@edef
调用只会重复这个过程:\cite
直到材料实际排版后才会展开(或者您忘记了安全使用\edef
!)。
这是如何工作的?嗯,\protect
并不总是有相同的定义。大多数情况下,它被定义为\relax
,所以什么也不做。然而,\protected@edef
将定义更改为
\noexpand\protect\noexpand
在 内部\edef
,这将保留 的存在\protect
(以允许多次\protected@edef
调用),然后将阻止下一个标记的扩展:我们想要保留的宏。
类似的考虑适用于\protected@xdef
和\protectd@write
,它们在扩展方面具有相同的问题。
所有这些都非常巧妙,但您必须记住使用,\protected@edef
并且在某些情况下保护会失败。出于这个原因,e-TeX 扩展包括\protected
原语,它定义了“引擎稳健”宏。这些宏永远不会在 内扩展\edef
,无需任何额外步骤。