为什么从内括号调用命令时我的参数设置为零?

为什么从内括号调用命令时我的参数设置为零?

我有一段代码:

\documentclass{scrartcl}
\usepackage{pbox,calc}

\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother

\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}

\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{
    \setlength{\souspointsExo}{#1pt}
    \setlength{\pointsSousTotal}{\pointsSousTotal + #1pt}
    {\scriptsize{(#1~\ifdim#1pt=1pt point\else points\fi/\strippt\pointsExo)}}
}

\newcommand{\subexo}[2]{
    \textsf{ %%If I comment these two lines, the sub-total is correct
        #1\hfill\sousPoints{#2}% Points
    }        %%If I comment these two lines, the sub-total is correct
    \medskip
}

\newcommand{\exercice}[2]{
    \setlength{\pointsExo}{#2pt}
    \setlength{\pointsSousTotal}{0pt}
    \medskip
    #1\hfill#2 Points% Points
    \medskip
}

\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}

\subexo{Something}{0.5}

Sub-Total: \strippt\pointsSousTotal %should display 2.5

\exercice{A title}{4}
\subexo{another thing}{2.5}

\subexo{and a thing}{1.5}

Sub-Total: \strippt\pointsSousTotal %should display 4

\end{document} 

问题是它应该显示如下内容:

第一个 2.5 分

任何事物(2 分/2.5)

某事(0.5 分/2.5)

小计:2.5

一个标题

另一件事 (2.5 分/4)

和一件事(1.5 分/4)

小计:4

但是,除非我注释掉指示的两行(目前,一个封闭的 \textsf{...},但只要我将 \sousPoints{#2} 括在两个花括号之间,问题就是一样的),否则我会得到这个:

第一个 2.5 分

任何事物(2 分/2.5)

某事(0.5 分/2.5)

小计:0

一个标题

另一件事 (2.5 分/4)

和一件事(1.5 分/4)

小计:0

在括号 {...} 内使用长度有什么问题?这是一个错误吗?对命令的工作方式理解不正确?

答案1

您需要进行全局分配才能在组外看到效果:

\documentclass{scrartcl}
\usepackage{pbox,calc}

\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother

\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}

\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{% don't let egreg get points for missing %
    \setlength{\souspointsExo}{#1pt}% don't let egreg get points for missing %
    \setlength{\pointsSousTotal}{\pointsSousTotal + #1pt}% don't let egreg get points for missing %
     \global\souspointsExo=\souspointsExo % a bit costly of save stack but unlikely to have 1000s of these.
     \global\pointsSousTotal=\pointsSousTotal
    {\scriptsize{(#1~\ifdim#1pt=1pt point\else points\fi/\strippt\pointsExo)}}% don't let egreg get points for missing %
}

\newcommand{\subexo}[2]{% don't let egreg get points for missing %
    \textsf{%%If I comment these two lines, the sub-total is correct
        #1\hfill\sousPoints{#2}% Points
    }%%If I comment these two lines, the sub-total is correct
    \medskip
}

\newcommand{\exercice}[2]{% don't let egreg get points for missing %
    \setlength{\pointsExo}{#2pt}% don't let egreg get points for missing %
    \setlength{\pointsSousTotal}{0pt}% don't let egreg get points for missing %
    \medskip
    #1\hfill#2 Points% Points
    \medskip
}

\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}

\subexo{Something}{0.5}

Sub-Total: \strippt\pointsSousTotal %should display 2.5

\exercice{A title}{4}
\subexo{another thing}{2.5}

\subexo{and a thing}{1.5}

Sub-Total: \strippt\pointsSousTotal %should display 4

\end{document} 

答案2

我在这里发布的是我做的一个补充测试。我发布它是为了演示 \setlength 在组内或组外时的效果(这是 David Carlisle 在我的问题的第一个评论中提出的一种可能的解决方案)。

不过,我更喜欢 David Carlisle 的 \global 答案。它允许在一个命令中显示和设置值(因为我永远不会在一个文档中调用超过 50 次此命令,所以它不会消​​耗太多资源)。

\documentclass{scrartcl}
\usepackage{pbox,calc}

\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother

\newlength{\pointsTotal}
\setlength{\pointsTotal}{0pt}


\newcounter{numExercice}
\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}

\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{% Will only display the points, not make the assignement
    {\scriptsize{(#1~\ifdim#1pt<2pt point\else points\fi/\strippt\pointsExo)}}%
}

\newcounter{sousExercice}[numExercice]
\newcommand{\subexo}[2]{%
    \stepcounter{sousExercice}%
    \setlength{\souspointsExo}{#2pt}%makes the assignment outside of the group, no global required
    \setlength{\pointsSousTotal}{\pointsSousTotal + #2pt}%makes the assignment outside of the group, no global required
    \medskip        
    \textsf{%
        \textbf{\arabic{numExercice}.\arabic{sousExercice}} :~#1%
        \hfill\sousPoints{#2}% Points
    }
}


\newcommand{\exercice}[2]{%
    \stepcounter{numExercice}%
    \setlength{\pointsExo}{#2pt}%
    \setlength{\pointsSousTotal}{0pt}%
    \setlength{\pointsTotal}{\pointsTotal + #2pt}%
    \medskip

    \textbf{Exercice \arabic{numExercice}} :~#1\hfill%
    {\normalsize{(#2~\ifdim#2pt<2pt point\else points\fi)}}% Points

    \medskip
}

\newcommand{\subtotal}{\strippt\pointsSousTotal}

\newcommand{\Total}{Total des points : \strippt\pointsTotal}

\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}

\subexo{Something}{0.5}

Sub-Total: \strippt\pointsSousTotal

\exercice{A title}{4}
\subexo{another thing}{2.5}

\subexo{and a thing}{1.5}

Sub-Total: \strippt\pointsSousTotal

\end{document} 

相关内容