指定键值的顺序重要吗?

指定键值的顺序重要吗?

以下屏幕截图显示了指定键值的顺序如何影响输出。

  1. 当使用dx=\psPiH,xunit=\psPi

    在此处输入图片描述

  2. 当使用xunit=\psPi,dx=\psPiH

    在此处输入图片描述

最小工作示例

\documentclass[pstricks]{standalone}
\usepackage{pst-plot}

\psset{trigLabels=true,trigLabelBase=2,}

\begin{document}

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[dx=\psPiH,xunit=\psPi](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}


\begin{pspicture}(-7,-2)(7,2)
    \psaxes[xunit=\psPi,dx=\psPiH](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}


\end{document}

这可能是一个错误。但是指定键值的顺序重要吗?

答案1

一般而言,当按键之间存在交互时,按键的顺序很重要。这是因为按键通常是按从左到右的方式处理的,因此列表中“较早”按键的设置可能会被“较晚”按键的设置所改变。

在某些情况下,内部实现会使用多遍方法来设置键。例如fontspec,通过 可以实现此目的,它首先检查所用字体的基本细节,然后设置适合该类型的键。

可以设置键值方法,使顺序无关紧要,例如,将它们解析为数组,然后按固定顺序使用。但是,大多数包都不会这样做,我希望使用此方法的任何包都能记录下来。

答案2

仅当键相互依赖时,顺序才重要。dx是 PSTricks 长度,可以使用或不使用单位。如果没有单位,则需要当前的的值psxunit!并且该值由键设置xunit。这就是预期的相对长度设置的行为!

使用dx绝对长度(具有像这样的单位\psPiH cm)可以使两个键独立:

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[dx=\psPiH cm,xunit=\psPi](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}

\begin{pspicture}(-7,-2)(7,2)
    \psaxes[xunit=\psPi,dx=\psPiH cm](0,0)(-2.2,-1)(2.2,1)
\end{pspicture}

将给出相同的输出!

答案3

虽然任何键值系统看起来都是“设置属性”(例如,图片的数值参数),但实际上在某种程度上它们都是“调用方法”。我真的只知道pgfkeys,这不是你要问的,但在系统,键与 TeX 宏一样强大,因此可以具有任意复杂的行为。正如 Herbert 回答的那样,即使对于您的示例,一个键也会设置另一个键使用的默认值,即使对于基本上只是设置属性的键,这也是可以预料到的事情。

作为一个与 TeX 无关的编程问题,有可能使键与顺序无关,这将涉及为每个键设置一个标志并在实际操作之前存储其值。在列表的末尾,检查所有标志并通过大量条件语句解决所有交互,最后以列表中键所暗示的任何方式使用请求的值。由于这涉及手动验证所有可能的键组合,并且最终基本上只是建立默认顺序(如 Joseph 的回答中所述),因此更容易让给定的顺序成为默认顺序,这实际上是这样做的。

答案4

重新排列内部设置键的顺序(从用户键值列表)会很昂贵。设置列表两次可能会使列表的顺序变得不那么相关,但密钥作者必须谨慎行事。

让我们假设以下关键点。

\mp@a取决于后面的内容,所以我们必须在了解的条件下\mp@b进行评估:\mp@a\mp@b

\define@key{fam}{a}[1cm]{%
  \ifdefined\mp@b\edef\mp@a{\the\dimexpr#1+\mp@b}\fi
}
\define@key{fam}{b}[.5cm]{\def\mp@b{#1}}

直到设置\mp@a键之后,才会知道更新后的值。b

两次设置列表将使列表的顺序变得不那么相关。这可以通过以下方式实现

\newcount\setkeyscount
\def\setkeystwice{\@testopt\s@tkeystwice{KV}}
\def\s@tkeystwice[#1]#2#3{%
  \setkeyscount\z@
  \loop
    \setkeys[#1]{#2}{#3}%
    \advance\setkeyscount\@ne
    \ifnum\setkeyscount<\tw@
   \repeat
}

\setkeystwice{a=1cm,b=2cm}

这是一种更正式的方法,在定义键时不需要特殊条件。键作者只需按照\orderofkeys他希望键在内部设置的正确顺序进行调用即可。请注意,(i) \orderofkeys(实际上,\XKV@setheadkeys)不会从其预设列表中过滤掉“当前键”(即出现在用户提供的键值列表中的键);(ii)\orderofkeys采用键值列表,但用户可以省略具有默认值的键的值。

\documentclass{article}
\usepackage{xkeyval}
\makeatletter
\newcommand*\headkeys{\XKV@stfalse\XKV@testoptb\XKV@headkeys}
\def\XKV@headkeys#1{\XKV@pr@setkeys{#1}{headkeys}}
\let\orderofkeys\headkeys

% \setkeystwice[<pref>]{<fam>}[<na>]{<kvlist>}
\def\setkeystwice{\XKV@testopta{\XKV@testoptc\XKV@setkeystwice}}
\def\XKV@setkeystwice[#1]#2{%
  \ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
  \XKV@checksanitizea{#2}\XKV@tempb
  \let\XKV@naa\@empty
  \XKV@for@o\XKV@tempb\XKV@tempa{%
    \expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
    \XKV@addtolist@x\XKV@naa\XKV@tempa
  }%
  \expandafter\XKV@s@tkeystwice\expandafter{\XKV@tempb}{#1}%
}
\def\XKV@s@tkeystwice#1#2{%
  \XKV@setheadkeys{#2}%
  % Set the usual xkeyval's head keys:
  \XKV@usepresetkeys{#2}{preseth}%
  \XKV@s@tkeys{#1}{#2}%
  \XKV@s@tkeys{#1}{#2}%
  % Set the usual xkeyval's tail keys:
  \XKV@usepresetkeys{#2}{presett}%
  \let\CurrentOption\@empty
}
% Unlike xkeyval package's \XKV@usepresetkeys, \XKV@setheadkeys instantiates 
% head/ordered keys whether or not they appear in the current (user-supplied) key-value
% list.
\def\XKV@setheadkeys#1{%
  \XKV@presettrue
  \XKV@for@eo\XKV@fams\XKV@tfam{%
    \XKV@makehd\XKV@tfam
    \XKV@ifundefined{XKV@\XKV@header headkeys}{}{%
      \XKV@toks\expandafter\expandafter\expandafter
        {\csname XKV@\XKV@header headkeys\endcsname}%
      \@expandtwoargs\XKV@s@tkeys{\the\XKV@toks}{#1}%
    }%
  }%
  \XKV@presetfalse
}

% Example use:

% We could have used command-keys to define these keys, but never mind:
\define@key{box}{boxwidth}[1cm]{\def\boxwidth{#1}}
\define@key{box}{boxheight}[.5cm]{\def\boxheight{#1}}
\define@key{box}{framecolor}[black]{\def\framecolor{#1}}
\define@key{box}{shadecolor}[white]{\def\shadecolor{#1}}
\define@key{box}{shadowcolor}[gray]{\def\shadowcolor{#1}}
\define@key{box}{framesize}[.4pt]{\def\framesize{#1}}
\define@key{box}{boxsep}[5mm]{\def\boxsep{#1}}
% Note: \shadowsize is a fraction of \boxwidth plus \boxheight. [The ratio is given by 
% the key 'shadowratio'.] Hence 'boxwidth' and 'boxheight' must be set before     
% 'shadowratio'. We want to allow the user to set the keys in any order.
\define@key{box}{shadowratio}[.25]{%
  \def\tempa##1.##2\@nil{##1}%
  \edef\tempa{\expandafter\tempa\the\dimexpr#1pt*100\relax\@nil}%
  \edef\shadowsize{\the\dimexpr(\boxwidth+\boxheight)/\tempa}%
}

% Since the values of 'boxwidth' and 'boxheight' are needed when setting 'shadowratio',
% we preset/order 'boxwidth' and 'boxheight' before 'shadowratio'. The user could then
% set the keys in any order he likes.
\orderofkeys{box}{boxwidth,boxheight,shadowratio,framecolor,shadecolor,
  shadowcolor,framesize,boxsep}

% Let us define a sample method that uses these keys and \setkeystwice:
\usepackage{xcolor}
\newcommand*\somebox[2][]{%
  \setkeystwice{box}{#1}%
  \begingroup
  \fboxrule=\framesize\relax
  \setbox0=\hbox{%
    \fcolorbox{\framecolor}{\shadecolor}{%
      \vbox to \boxheight{\vfil\hbox to\boxwidth{\hfil{#2}\hfil}\vfil}%
    }%
  }%
  \hskip\shadowsize\hskip\boxsep
  \color{\shadowcolor}%
  \rule[-\dp0]{\wd0}{\the\dimexpr\ht0+\dp0\relax}%
  \llap{\raisebox{\shadowsize}{\box0\hskip\shadowsize}}%
  \endgroup
}
\makeatother

\begin{document}
% Now the user may set the keys in any order he wishes.
\somebox[boxwidth=1cm,boxheight=.5cm,shadowratio=.25,framesize=1pt]{box 1}
\somebox[boxwidth=2cm,boxheight=1cm,shadowratio=.1,
  framesize=2pt,framecolor=green,shadowcolor=blue]{box 2}
\end{document}

相关内容