\edef 和内部 \def 错误,

\edef 和内部 \def 错误,

我似乎不太理解宏定义\edef与另一个定义中的宏定义的组合。最好用一个例子来说明。

以下 MWE(我知道它不是很有用,所以很少)不起作用:

\documentclass{article}
\def\mymacro#1{%
    \def\do##1{##1}%
    #1%
}

\begin{document}
    \edef\savedValue{\mymacro{argument}}%
    savedValue: \savedValue
\end{document}

错误出在行\edef和状态中Illegal parameter number in definition of \savedValue

我以为\edef会扩展\mymacro{argument},它首先扩展\def\do##1{##1}为零,导致输出argument,然后保存到\savedValue。如果没有该行,\def\do##1{##1}这似乎可以按解释工作,但是有了该行,我得到了上述错误。

这里有什么问题?

使用xparse命令确实有效

\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\mymacro}{m}{%
    \def\do##1{##1}%
    #1%
}

\begin{document}
    \edef\savedValue{\mymacro{argument}}%
    savedValue: \savedValue
\end{document}

并给出预期的输出:结果

使用的实际区别是什么\def

答案1

操作\def不可扩展。在 中\edef \def只是一个保持不变的不可扩展标记。同样,\mymacro最终被定义为,\protected\def因此在 中不扩展\edef

\show\mymacro

节目

> \mymacro=\protected macro:
#1->\def \do ##1{##1}#1.
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\mymacro}{m}{%
    \def\do##1{##1}%
    #1%
}

\begin{document}
    \edef\savedValue{\mymacro{argument}}%
    savedValue: \savedValue
\end{document}

因此,的定义中没有可扩展的标记,\savedValue因此在这种情况下\edef,相当于\def\show\savedValue显示

   > \savedValue=macro:
->\mymacro {argument}.

然后当\savedValue展开时它相当于

\def\do#1{#1}argument

如果你使用\def而不是\protected\def那么当你到达扩展\edef mymacro(但\def没有所以它是一样的

\edef\savedValue{\mymacro{argument}}%

\edef\savedValue{\def\do##1{##1}argument}%

然后它尝试扩展\def,但无法扩展,所以它被留下,然后它尝试扩展,所以你得到此时\do随机定义的扩展,恰好是\do

 \do=\noexpand.

事情出错了……

答案2

避免 David Carlisle 解释的问题的另一种可能性是完全避免\edef。诀窍是将保存放在“被调用函数”内部。这有点类似于 C,其中指向分配内存的指针作为函数的第一个参数给出,通常是输入输出参数。这种模式可能可以为 LaTeX 省去很多麻烦。

\documentclass{article}
\usepackage{etoolbox}
\def\mymacro#1#2{%
    \def\do##1{##1}%
    \csdef{#1}{#2}%
}

\begin{document}
    \mymacro{savedValue}{argument}%
    savedValue: \savedValue
\end{document}

答案3

您的代码是:

\documentclass{article}
\def\mymacro#1{%
    \def\do##1{##1}%
    #1%
}

\begin{document}
    \edef\savedValue{\mymacro{argument}}%
    savedValue: \savedValue
\end{document}

有两个事实与这一解释相关:

  1. 当宏被展开时⟨定义文本⟩包含哈希序列,那么在扩展宏的结果中,这些序列中的哈希数量将减半。
    使用示例的代码可得出 。所有序列中的哈希数量\mymacro{⟨argument⟩}\def\do#1{#1}⟨argument⟩##⟨定义文本⟩将展开后的结果\mymacro减半为。#\mymacro

  2. \def不可扩展,因此不会从标记流中删除,但在 -expansion 期间将保持不变\edef。(除非可扩展控制序列在\edef-expansion 期间被扩展,其扩展导致 -token 被删除,\def如下所示\gobble\def\gobble#1{} ... \edef\foo{\gobble\def whatsoever}。)

随着\edef\savedValue{\mymacro{argument}}可扩展标记序列的\mymacro{argument}扩展,直到分配完成之前没有剩余的可扩展标记。

\def不可扩展。因此,只需扩展所有可扩展标记即可\mymacro{argument}

\def⟨total expansion of all expandable tokens in the sequence "\do#1{#1}argument" ⟩

如果\do被定义为不可扩展的东西,那么只需扩展所有可扩展的标记即可\mymacro{argument}得到标记序列:
\def\do#1{#1}argument

\edef在-扩展过程中产生的 token 序列很有可能是扩展的⟨定义文本⟩ 包含#1尽管⟨参数文本⟩的定义\edef\savedValue空/没有引入参数#1

这就是你收到错误的原因Illegal parameter number in definition of \savedValue.

如果\do未定义,您将收到错误

! Undefined control sequence.
\mymacro #1->\def \do

发生错误之前Illegal parameter number in definition of \savedValue.



下面的例子也许能让你更好地理解它的\edef工作原理:

\documentclass{article}
\def\mymacro#1{%
  \def\do{#1}%
}
\begin{document}
\let\do=\relax 
\edef\macro{\mymacro{bar}}
\show\macro
\let\foo=\relax
\def\do{\foo}%
\edef\macro{\mymacro{bar}}
\show\macro
\def\foo{\hoo}%
\let\hoo=\relax
\edef\macro{\mymacro{bar}}
\show\macro
\end{document}    

控制台输出:

[...]
> \macro=macro:
->\def \do {bar}.
l.8 \show\macro
               
? 
> \macro=macro:
->\def \foo {bar}.
l.12 \show\macro
                
? 
> \macro=macro:
->\def \hoo {bar}.
l.16 \show\macro
                
? 
[...]

下面的例子可能有助于更好地理解扩展过程中哈希序列的处理:

\documentclass{article}

\makeatletter
\newcommand\stringifytillrelax[1]{%
  \ifx\relax#1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {}{\string#1\stringifytillrelax}
}%
\makeatother

\begin{document}
\def\mymacro{##}%
\message{^^JSee the amount of hashes that comes from expanding \string\mymacro: \expandafter\stringifytillrelax\mymacro\relax}%
\def\mymacro{####}%
\message{^^JSee the amount of hashes that comes from expanding \string\mymacro: \expandafter\stringifytillrelax\mymacro\relax}%
\def\mymacro{######}%
\message{^^JSee the amount of hashes that comes from expanding \string\mymacro: \expandafter\stringifytillrelax\mymacro\relax}%
\def\mymacro{########}%
\message{^^JSee the amount of hashes that comes from expanding \string\mymacro: \expandafter\stringifytillrelax\mymacro\relax}%
\edef\mymacrob{\mymacro}
\message{^^JSee the amount of hashes that comes from expanding \string\mymacrob: \expandafter\stringifytillrelax\mymacrob\relax}%
\edef\mymacroc{\mymacrob}
\message{^^JSee the amount of hashes that comes from expanding \string\mymacroc: \expandafter\stringifytillrelax\mymacroc\relax}%
\end{document}    

控制台输出:

[...]
See the amount of hashes that comes from expanding \mymacro: # 

See the amount of hashes that comes from expanding \mymacro: ## 

See the amount of hashes that comes from expanding \mymacro: ### 

See the amount of hashes that comes from expanding \mymacro: #### 

See the amount of hashes that comes from expanding \mymacrob: ## 

See the amount of hashes that comes from expanding \mymacroc: #
[...]

相关内容