在 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
定义文本宏有三种可能:
\def\dosomething#1{\textbf{#1}}
\def\dosomething{\textbf}
\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 更改。