为什么\ifx
测试给出的答案与\ifthenelse
以下简单示例不同?
testclass.cls(不含头和尾):
\newcommand{\isempty}{\@empty}
\ifthenelse{\equal{\isempty}{\@empty}}
{\newcommand{\foo}{ifthen says yes}}
{\newcommand{\foo}{ifthen says no}}
\ifx\isempty\@empty
\newcommand{\foofoo}{ifx says yes}
\else\newcommand{\foofoo}{ifx says no}
\fi
现在,如果我在 .tex 文件中调用命令\foo
,\foofoo
我将得到以下输出:
ifthen 说是
ifx 说不
为什么?区别在哪里?我以为以下两个是等效的:
\ifx\macroA\macroB\DoSomething\else\DoSomethingElse\fi
\ifthenelse{\equal{\macroA}{\macroB}}{\DoSomething}{\DoSomethingElse}
是否存在一些扩展问题?
答案1
首先,
\newcommand{\isempty}{\@empty}
考试
\ifx\isempty\@empty
将返回 false,因为
- 和
\isempty
都是\@empty
宏,但是 - 他们的地位不同
\long
。
然而,这也会\newcommand*{\isempty}{\@empty}
导致测试失败,因为
- 和
\isempty
都是\@empty
宏,状态相同\long
(都不是\long
),但是 - 它们在第一级扩展上有所不同,第一级扩展
\@empty
为,而 则为\isempty
,并且 没有任何意义\@empty
。
当然,这假设您的代码前面有\makeatletter
。
为什么\ifthenelse{\equal{\isempty}{\@empty}
遵循真正的分支?因为测试确实满的参数的展开\equal
。在两个参数中,完整展开都是空的。来自包文档:
这 ⟨细绳测试的⟩s
\equal
可以是任何扩展为标记列表的命令序列。如果这些扩展相等,则命题为真。
基本上,\ifx
测试后面的两个 token 在\meaning
应用时是否会产生相同的结果。在
\makeatletter
\newcommand{\isempty}{\@empty}
执行\meaning\isempty
将会打印
\long macro:->\@empty
while\meaning\@empty
会打印
macro:->
因此您会看到,就其\ifx
本身而言,它们是不同的。
如果你的代码之前没有这个\makeatletter
,情况会稍微复杂一些:
的完整展开
\@empty
,长度为 6 个 token,是\spacefactor \@m empty
由于
\isempty
首先扩展为\@empty
,\ifthenelse
测试无论如何都会遵循真正的分支;测试
\ifx
将\isempty
与进行比较\@
,返回 false,因此empty
将与真实文本一起消失,并遵循错误分支。