csnumgdef 有什么作用?

csnumgdef 有什么作用?

它做什么\csnumgdef?从代码示例来看,它似乎需要两个参数,并且让人相信它定义了一个数字var并为其分配了值val,如\csnumgdef{var}{val}。如果var被用作一个简单的计数器,那么这种语法与以下语法相比有哪些优点/缺点:

\newcounter{var}
\setcounter{var}{val}

最后, 的词源是什么csnumgdef,特别是csg?我注意到其他命令似乎属于这个cs家族,例如\csname\csuse\csdef,但我不清楚是什么将它们联系在一起。

答案1

\csnumgdef,来自etoolbox包(对您来说,由 加载biblatex)的 定义为:

\newrobustcmd*{\csnumgdef}[1]{%
  \expandafter\numgdef\csname#1\endcsname}

\numgdef定义为:

\newrobustcmd*{\numgdef}[2]{%
  \ifundef#1{\let#1\z@}{}%
  \xdef#1{\the\numexpr#2}}

让我们一步一步地看一个例子。假设你做了\csnumgdef{foo}{1+1}。首先,\csnumgdef接受一个参数,foo然后执行({1+1}上一步的 仍然存在,未发生任何变化):

\expandafter\numgdef\csname foo\endcsname{1+1}

跳过并扩展。构建一个控制序列(因此名称中的) \expandafter,其中包含匹配的,即参数。这变成:\numgdef\csname\csnamecs\csnumgdef\endcsnamefoo

\numgdef\foo{1+1}

因此你可以得出结论\csnumgdef{foo}\numgdef\foo是等价的。

现在\numgdef展开,抓住两个参数,\foo1+1

\ifundef\foo{\let\foo\z@}{}%
\xdef\foo{\the\numexpr 1+1}

测试\ifundef检查是否\foo未定义,如果\let\foo\z@是则执行操作,否则不执行任何操作。

现在来看看好的部分:\xdef相当于\global\edef(现在您看到gin代表),它将进行全局分配,并将扩展定义内的所有内容。它将扩展(cs)numgdef\global\edef\the,这将触发\numexpr\numexpr然后将评估其后的整数表达式(1+1)并将结果保留在那里。扩展后,您将得到(某种程度上):

\global\def\foo{2}

现在一切照常,并且现在\foo扩展到2


简而言之,\csnumgdef{<name>}{<intexpr>}将计算整数表达式<intexpr>并将其存储在中\<name>。名称中不带的版本cs将控制序列作为参数(而不是控制序列名称):,\numgdef\<name>{<intexpr>}而没有的版本g执行本地赋值。


这些命名约定很有用(尤其是正确遵循时 ;-),因为您不需要查找某个命令的定义来了解它的作用。如果您知道它的作用,那么推断出它的作用\numdef\foo{1+1}并不难(当然,前提是您知道这些约定)。\csnumdef\numgdef

expl3的约定定义一个函数,set其名称中包含 ,则执行赋值(与defin非常相似\numdef)。如果函数是 ,gset则这种赋值是全局的。知道这一点,很容易猜出\int_set:Nn做什么:它(几乎1)与 相同\numdef:-)
如果您知道这一点,那么\int_gset:Nn就很容易了。

但是你会问,版本呢cs?这个是在参数规范中表示的。N参数不是单个常规参数,而是csname。\int_set:cn(equivalent of \csnumdef) 和\int_gset:cn(equivalent of \csnumgdef) 就是这样做的 :-)

1 \numdef将数字存储在宏中,而\int_set:Nn将其存储在计数寄存器中。

答案2

\csnumgdef定义在etoolbox包裹。该软件包“是一个编程工具箱,主要面向 LaTeX 类和软件包作者。它为 e-TeX 提供的一些新原语提供了 LaTeX 前端,以及一些与 e-TeX 无关但符合该软件包配置的通用工具。”(摘自etoolbox文档

cs和命名gdef在整个文档中使用,大致定义为

  • cs=<csname>
  • g =g全局
  • def=\def

另一种解释是gdef类似于\gdef\global\def(或可能\xdef——x的扩展版本\gdef)。


在某些情况下,只考虑控制序列名称(例如,foo),而不是控制序列本身(例如,\foo)会更方便。例如,也许您想要定义一个辅助控制序列,该序列应伴随某些定义,并且为了编码的目的,您使用相同的基本定义。以下是一个例子:

\makeatletter
\newcommand{\foo}{foo}
\newcommand{\foo@bar}{bar}
\newcommand{\print}[1]{\csname #1\endcsname: \csname #1@bar\endcsname}
\makeatother

\print{foo}

打印

foo:酒吧

很容易传递foo\print然后访问\foo@bar。但是,如果您已传递\foo\print,则必须删除反斜杠\才能在字符串中添加后缀@bar并访问\foo@bar。因此,根据用户(包作者)的不同,使用控制序列名称可能比使用控制序列本身更方便。


etoolbox\csnumgdef{<var>}{<val>}明确定义其中一些函数以强制特定用途。

\newcounter{<var>}
\setcounter{<var>}{<val>}

因为<var>in\csnumgdef不是计数器。相反,它是一个常规控制序列。但是,由于<val>使用 进行评估\numexpr,因此只接受在该上下文中有效的参数。因此,它看起来可能类似于使用计数器,但内部是不同的。由于它使用\numexpr,您可以执行类似操作\csnumgdef{foo}{5+2}并将7存储在 中\foo。如果您已经定义了计数器,则无需\thefoo打印数字。

相关内容