有这个\newsetter
宏,它定义了一个“setter”宏(因为没有更好的名字)和一个同名的 @ 前缀宏,用于保存值。它应该这样工作:
\newsetter\macro
\macro{foo}
\@macro % expands to foo
\macro{bar}
\@macro % expands to bar
代码如下\newsetter
:
\newcommand\newsetter[1]{%
\@temptokena=\expandafter{\expandafter\@gobble\string #1}%
\expandafter\newcommand\csname @\the\@temptokena\endcsname{}%
\expandafter\newcommand\csname\the\@temptokena\endcsname[1]{%
\expandafter\renewcommand\csname @\the\@temptokena\endcsname{##1}}}%
此代码的问题在于它只能按特定顺序起作用:
\newsetter\firstword
\firstword{Hello}
\newsetter\secondword
\secondword{World}
\@firstword\ \@secondword % expands to Hello World
而以下操作失败:
\newsetter\firstword
\newsetter\secondword
\firstword{Hello}
\secondword{World}
\@firstword\ \@secondword % expands to World, \@firstword is empty
这里有什么问题?
答案1
您已定义\firrstword
(例如)为
> \firstword=\long macro:
#1->\expandafter \renewcommand \csname @\the \@temptokena \endcsname {#1}.
l.12 \show\firstword
这意味着\firstword
并不定义\@firstword
而是基于 的当前值的命令\@temptokena
。如果你使用 toks 寄存器,则需要提前扩展它,以便\firstword
根据其值进行定义,或者更简单地根本不使用 toks 寄存器:
\makeatletter
\newcommand\newsetter[1]{%
\@temptokena=\expandafter{}%
\expandafter\newcommand\csname @\expandafter\@gobble\string #1\endcsname{}%
\expandafter\newcommand\csname\expandafter\@gobble\string #1\endcsname[1]{%
\expandafter\renewcommand\csname @\expandafter\@gobble\string #1\endcsname{##1}}}%
\newsetter\firstword
\newsetter\secondword
\firstword{Hello}
\secondword{World}
\show\@firstword
\show\@secondword
\stop