嵌套 \newcommand 和 \renewcommand

嵌套 \newcommand 和 \renewcommand

阅读该课程时twentysecondcv.cls我注意到有一个命令是这样定义的:

\newcommand\skills[1]{
    \renewcommand{\skills}{
        \begin{tikzpicture}
            \foreach [count=\i] \x/\y in {#1}{
                \draw[fill=maingray,maingray] (0,\i) rectangle (6,\i+0.4);
                \draw[fill=white,mainblue](0,\i) rectangle (\y,\i+0.4);
                \node [above right] at (0,\i+0.4) {\x};
            }
        \end{tikzpicture}
    }
}

嵌套\renewcommand里面\newcommand是做什么用的?

完整的课程是在 GitHub 上

答案1

以这种方式定义\skills的效果是,在第一次使用时,它需要一个参数。然后skills重新定义为存储此值(加上一些处理),以便从现在开始,命令(无参数)将重现第一次调用时设置的内容。

举个例子,

\newcommand\myname[1]{\renewcommand\myname{#1}}

当你执行

\myname{Stefano} % corresponds to \renewcommand\myname{Stefano}

然后从此刻起\myname代表,即每次使用 都将被排版。Stefano\mynameStefano

答案2

TeX 没有变量本身与其他编程语言一样。有专用寄存器用于保存计数(整数)、维度、输入和输出流、标记列表等内容。但大多数情况下,所有内容都是以宏的形式定义的。这意味着,要将信息保存在变量中,需要定义一个宏。

这里所做的是非惯用的和有限的,因为现在命令\skills已经不可逆转地改变了它的含义,并且该类的新手用户如果使用\skills两次就会发现意想不到的结果。通常,人们不会重新定义命令,而是会做这样的事情:

\newcommand\skills[1]{
    \def\@skills{
        \begin{tikzpicture}
            \foreach [count=\i] \x/\y in {#1}{
                \draw[fill=maingray,maingray] (0,\i) rectangle (6,\i+0.4);
                \draw[fill=white,mainblue](0,\i) rectangle (\y,\i+0.4);
                \node [above right] at (0,\i+0.4) {\x};
            }
        \end{tikzpicture}
    }
}

它将存储该值\@skills以供稍后使用(在此文档类中,稍后的使用来自命令\makeprofile定义。

事实上,更惯用的做法是

\newcommand\skills[1]{\def\@skills{#1}}

然后将整个tikzpicture环境移至\makeprofile定义。

答案3

该命令\makeprofile定义为

\newcommand{\makeprofile}{
    \begin{tikzpicture}[remember picture,overlay]
        \node [rectangle, fill=sidecolor, anchor=north, minimum width=9cm, minimum height=\paperheight+1cm] (box) at (-5cm,0.5cm){};
    \end{tikzpicture}

    %------------------------------------------------

    \begin{textblock}{6}(0.5, 0.2)
[...irrelevant code...]
        \profilesection{Skills}

        \skills
        \skillstext
        \scriptsize
        %(*)[The skill scale is from 0 (Fundamental Awareness) to 6 (Expert).]
            
        %------------------------------------------------
            
    \end{textblock}
}

你应该\skills{x,y,z}在做之前说\makeprofile

我认为这不是一个好的编程,因为它无法检查错误。

最好这样做

\newcommand{\skills}[1]{%
  \def\twentysecondscv@skills{...#1...}%
}

\makeprofile不是\skills调用

\ifdefined\twentysecondscv@skills
  \twentysecondscv@skills
\else
  \ClassError{twentysecondscv}
    {No \protect\skills found}
    {You need to define \protect\skills before doing \protect\makeprofile}%
\fi

有了此代码,错误消息就会准确地指出到底出了什么问题。

\skillstext在提供的模板中似乎也没有使用过。如果忘记了\skills,那么调用\makeprofile只会吞掉\skillstext。如果没有\skilltext出现命令,它将吞噬\scriptsize,这似乎只是为了被吞掉或被完全忽略。

甚至更好

\newcommand{\skills}[1]{%
  \def\twentysecondscv@skills{...#1...}%
  \renewcommand{\skills}[1]{\twentysecondscv@repeat{\skills}}%
}
\newcommand{\twentysecondscv@repeat}[1]{%
  \ClassError{twentysecondscv}
    {Multiple \protect#1 ignored}
    {You should have just one \protect#1 command}%
}

where\twentisecondscv@repeat也可以用于其他只应发出一次的命令。

相关内容