巢狀 \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}

then \mynamewill 代表Stefano從這一刻起,即每次使用\mynamewill typeset Stefano

答案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也可以用於其他應該只發出一次的命令。

相關內容