定义文本命令的首选方式(带或不带参数)

定义文本命令的首选方式(带或不带参数)

在 latex 中定义新的文本宏时,下列哪个声明是首选

\newcommand*{\dosomething}[1]{\textbf{#1}}

相对

\newcommand*{\dosomething}{\textbf}

textbf只是用作示例。我知道后一种构造在组内使用时是不允许的,例如

\newcommand*{\dosomething}{\begingroup\textbf\endgroup}

这些宏声明中是否存在其他问题?

答案1

表格

\newcommand*{\dosomething}[1]{\textbf{#1}}

稍慢于

\newcommand*{\dosomething}{\textbf}

因为使用第一种形式,参数被读入只是为了再次输入给\textbf

另一方面,第一种形式更清晰,因为它显示了预期的含义。如果你计划稍后修改它,那也更好,但这并不重要。

当 TeX 找到一个宏时,它知道该宏定义了多少个参数,因此它会查找这些参数并继续用该宏的替换文本替换标记。

因此,使用第二种形式,\dosomething{xyz}会让 TeX\dosomething用替换\textbf并继续查找 的参数\textbf

对于第一种形式,\dosomething{xyz}将被 替换\textbf{xyz},并且 TeX 会再次寻找 的参数\textbf;这解释了为什么第一种形式较慢(可能要慢几纳秒)。

请注意,第三种形式是不正确的,因为\endgroup会作为的参数输入\textbf,而这并不是一件可取的事情。

开玩笑地说,使用第二种形式表明你要么是男子汉,要么是货物崇拜者 LaTeX 程序员。其余代码会告诉你你属于哪一类。


还有另一种可能性,但它有几个缺点:

\let\dosomething\textbf

问题 1.它没有在 LaTeX 手册中记录,并且与 不同\newcommand,它不会检查是否\dosomething已经有定义。

问题2。如果你改变了 的含义\textbf(比如说你的内部风格要求粗体字始终保持直立),那么在指令\textbf之前或之后对 的改变就很重要了\let。当然,这可能被认为是一个愚蠢的例子,但它给出了这个想法。

的确,\let 冻结第二个标记的含义,因为第一个标记(在本例中\dosomething)假设当前的第二个标记的含义(在本例中为\textbf)。第二个标记含义的后续变化不会反映在第一个标记中。\newcommand上述任何一种策略都不会发生这种情况。

该命令有其用途,但它应该很少出现在文档序言中,通常以涉及重新定义的特殊目的的\let形式出现。\let\foo\relax\foo

问题 3。无论如何,如果您对 LaTeX 宏的工作原理没有深入的了解,则不建议使用,尤其是修改宏的行为以保持其当前含义(有关更多信息,\let请参阅包的文档) 。letltxmacro

答案2

正如 egreg 所指出的,使用第一种形式通常更清楚(但仅*当您打算消除参数中出现空行的可能性时才使用)

也就是说,这实际上是一个编码风格的选择问题,并且 Latex 内部到处都使用第二种形式。\textbf例如,它本身并不接受参数,正如您所看到的\show

*\show\textbf
> \textbf=macro:
->\protect \textbf  .
<*> \show\textbf

\textbf不带参数地扩展为两个标记|\protect||\textbf |(注意空格),并且后一个命令实际上有一个#1参数。

答案3

如果我们不需要检查定义的控制序列的名称,那么您的问题可以通过和原语
来改写:\def\let

定义文本宏有三种可能:

  1. \def\dosomething#1{\textbf{#1}}
  2. \def\dosomething{\textbf}
  3. \let\dosomething=\textbf

如果可能的话,我更喜欢第三种,即如果新序列将
采用一个已知“静态”序列的含义。当然,第二种和第三种变体并不相同:如果有人
\textbf\def或之后更改了 的含义\let \dosomething,则if\dosomething保留
其原始含义,但 if被使用时\let它会改变其含义。\def

如果我需要将一个 token 替换为多个 token,那么我会使用第一个或第二个替代方案;如果可能的话,第二个是首选。例如:

\def\mbox{\leavevmode\hbox}

这保留了原语使用的特殊参数扫描,\hbox并保留了参数内部的 catcode 变化。例如,用户不仅可以写入\mbox{...},还可以写入\mbox to2em{...}。另一方面,LaTeX 内核定义

\long\def\mbox#1{\leavevmode\hbox{#1}}

因此您无法执行此操作\mbox to2em{...},也无法在参数内部执行 catcode 更改。

相关内容