\@namedef 和 \@nameuse 的正确用法

\@namedef 和 \@nameuse 的正确用法

在一个上一个问题我问过如何循环生成多个保存框。答案围绕构建csname,里面的部分csname相当长,我需要多次使用名称(创建框、填充框、获取属性并使用它)。因此我想缩短它。我试过了

\makeatletter
...
\@namedef{saveBox}{<what was inbetween \csname \endcsname>}
...
\expandafter\newsavebox\@nameuse{saveBox}
...
\makeatother

这对我来说不起作用。如果能提供一些关于内部运作/一般用途的简短背景信息就更好了。


答案给我留下了一个问题,我无法让该\def版本与直接版本一起工作,请参阅示例以获取说明:

\def\floatRow@currentSaveBox{floatRow@savebox\alph{floatRow@rowImageCount}}
%\expandafter\newsavebox\csname\floatRow@currentSaveBox\endcsname   %works
\expandafter\newsavebox\csname{}floatRow@savebox\alph{floatRow@saveboxCount}\endcsname  %gives mising number error

我认为我对\commandName和 字符串的分离floatRow@savebox是错误的。以下是 MWE:

\documentclass{report}
\begin{document}
\newcounter{c}
\def\currentSBox{prefix\alph{c}}
\expandafter\newsavebox\csname\currentSBox\endcsname
\expandafter\savebox\csname\currentSBox\endcsname{dummy}
\expandafter\usebox\csname\currentSBox\endcsname
\expandafter\usebox\csname{}prefix\alph{c}\endcsname
\end{document}

答案1

让我们看看这里发生了什么。构造

\@namedef{saveBox}{<what was inbetween \csname \endcsname>}

定义\saveBox为带有替换文本的宏<what was inbetween \csname \endcsname>。这是因为\@namedef定义为

#1->\expandafter\def\csname #1\endcsname

这意味着它首先会将#1saveBox在你的情况下)转换为控制序列(\saveBox这里),然后应用\def。因此,它变得与执行

\def\saveBox{<what was inbetween \csname \endcsname>}

这是一件很有用的事情,但在当前情况下实际上并不是您想要的!

第二行

\expandafter\newsavebox\@nameuse{saveBox}

会因为多种原因而严重失败,正如评论中提到的那样。\@nameuse是一个包装器\csname ...\endcsname,因此只需一次扩展就可以

\newsavebox\csname saveBox\endscsname

尝试将其定义\csname为一个新的框!如果我们进行两次扩展,我们就会得到

\newsavebox\saveBox

这仍然是错误的,因为您已经将其定义\saveBox为宏。

根据链接的问题,你似乎想要的是更多形式

\def\my@name{MyString\@alph\count@}
\expandafter\newsavebox\csname\my@name\endcsname
...
\expandafter\usebox\csname\my@name\endcsname

IE将名称的形式保存在宏中并重复使用。


您可能想知道它\@nameuse有什么用处,因为它似乎使事情变得更加复杂而不是更简单(\@namedef很方便)。这至少部分是历史原因:当编写 LaTex2e 时,标记非常“昂贵”,因此当您查看内核中的所有用途时,节省\@nameuse(一个标记)而不是\csname ...\endcsname(两个标记)是值得的。今天,这不再那么重要了,尽管有一种观点认为

\def\foo#1{% Some function
  ...
  \@nameuse{my@#1}%
}

\def\foo#1{% Some function
  ...
  \csname my@#1\endcsname
}

因为它表明某些东西正在被使用,而不是通过名称来定义。


使用\@namedef更常见,因为它允许轻松构造“即时”名称。例如,我们可以想象存储一些用户输入:

\newcommand{\mycommand}[2]{%
  \@namedef{mycommand@store@#1}{#2}%
}

这可能会被用来保存一些用户信息:我将使用电子邮件地址,但它可以是任何东西

\mycommand{Joe Bloggs}{[email protected]}

如果你有一个更大的设置来执行此操作,比如存储有关几个“键”的几条数据,那么使用\@namedef比使用\expandafter\def\csname ...\mycommand{AN Other}{[电子邮件保护]}

相关内容