最小 \protected@edef 示例

最小 \protected@edef 示例

我最近在 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,无需任何额外步骤。

相关内容