以下屏幕截图显示了指定键值的顺序如何影响输出。
当使用
dx=\psPiH,xunit=\psPi
。当使用
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}