考虑以下类:
% CLASS
% Preamble
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesClass{myclass}[2022/10/11]
\LoadClass[varwidth]{standalone}
\makeatletter
% Pgfoptions
\RequirePackage{pgfopts}
\pgfkeys{
/myclass/.cd,
optionA/.store in = \myclass@optionA,
optionA = ,
optionB/.store in = \myclass@optionB,
optionB = \myclass@optionA,
}
\ProcessPgfOptions{/myclass}
\newcommand{\setA}[1]{\pgfkeyssetvalue{/myclass/optionA}{#1}\texttt{setA(#1)}\\}
\newcommand{\setB}[1]{\pgfkeyssetvalue{/myclass/optionB}{#1}\texttt{setB(#1)}\\}
\newcommand{\defineA}[1]{\pgfkeys{/myclass/optionA = #1}\texttt{defineA(#1)}\\}
\newcommand{\defineB}[1]{\pgfkeys{/myclass/optionB = #1}\texttt{defineB(#1)}\\}
\newcommand{\printoptions}{\fbox{\texttt{%
[A = (\pgfkeysvalueof{/myclass/optionA}, \myclass@optionA)]%
[B = (\pgfkeysvalueof{/myclass/optionB}, \myclass@optionB)]
}}\\}
\makeatother
在代码中使用:
\documentclass[optionA = A0]{myclass}
\begin{document}
\printoptions % => [A = (, A0)] [B = (, A0)]
\setA{A1}
\printoptions % => [A = (A1, A0)] [B = (, A0)]
\defineA{A2}
\printoptions % => [A = (A1, A2)] [B = (, A2)]
\setB{B1}
\printoptions % => [A = (A1, A2)] [B = (B1, A2)]
\defineB{B2}
\printoptions % => [A = (A1, A2)] [B = (B1, A2)]
\end{document}
有很多事情我不明白:
问题 0:为什么\pgfkeyssetvalue{/myclass/optionX}{#1}
和\pgfkeys{/myclass/optionX = #1}
会导致不同的结果?
问题 1:为什么打印\pgfkeysvalueof{/myclass/optionX}
和\myclass@optionX
会导致不同的结果,而我期望.store in
使两者等价?
问题2:为什么defineA(A2)
还要改变的值\myclass@optionB
?我原本以为optionB = \myclass@optionA
在定义期间pgfkeys
只是初始化,而不是两者之间的永久链接。
问题 3:有没有办法将和pgfkeys
同义词定义为始终对应于相同的值,例如包括通过或的改变?\pgfkeysvalueof{/myclass/optionX}
\myclass@optionX
\pgfkeyssetvalue{/myclass/optionX}
\pgfkeys{/myclass/optionX = XN}
问题 4:如何初始化pgfkeys
以便optionB = \myclass@optionA
仅\myclass@optionB
使用 的值进行初始化\myclass@optionA
(但如果\myclass@optionA
稍后更改,则不会改变 给出的值\myclass@optionB
),如下所示:
\printoptions % => [A = (, A0)] [B = (, A0)]
\setA{A1}
\printoptions % => [A = (A1, A0)] [B = (, A0)]
\defineA{A2}
\printoptions % => [A = (A1, A2)] [B = (, A0)] % Difference here: B stays the same!!!!
\setB{B1}
\printoptions % => [A = (A1, A2)] [B = (B1, A0)]
\defineB{B2}
\printoptions % => [A = (A1, A2)] [B = (B1, A0)]
pgfkeys
更一般地说,我认为我忽略了和关联背后发生的事情的大局macros
,因此任何大局解释都将受到赞赏。
答案1
这试图成为“全局”答案,即使这个答案仅关注的一个方面pgfkeys
,即如何存储赋予键的值以供以后使用:.store in
和\pgfkeyssetvalue
/ .initial
。
一般来说pgfkeys
有两种方式来存储值:
- 将值存储在键路径中
- 将值存储在某个宏中
您可以通过使用.initial
处理程序定义键(\pgfkeys{/foo/.initial = 1}
)来实现第一个目标,然后使用\pgfkeysvalueof
或访问值\pgfkeysgetvalue
。这只是将宏隐藏在一个不明显的名称中并增加了一个间接级别,其优点是使用与设置键相同的名称来获取其值,而不是另一个宏名称。
第二个是.store in
设置,所以\pgfkeys{/foo/.store in = \foo}
。这样设置,每次设置键时,的定义\foo
都会更改为扩展为给定值。优点是您可以更好地控制存储内容的位置,并且更轻松地扩展它。缺点是同一事物的另一个名称。
当您使用时,\pgfkeyssetvalue{/foo}{bar}
您仅分配给第一个存储,您不会调用处理程序设置的代码.store in
,因此不会对进行分配\foo
,而只会对关键路径进行分配/foo
。
你更喜欢哪一个(以及应该更喜欢哪一个)并不是规定的,pgfkeys
而是把选择权交给用户。虽然这个选择本身这不是什么坏事,但有时(比如你的情况)会导致混乱。我建议选择其中一种机制,并在一个项目中坚持使用(这并不意味着同一作者的另一个项目不能使用另一种方法)。
就我个人而言,我更喜欢第二种方法,因为我看不到这种间接级别的收益(以及我自己的 key=value 实现——广告块: expkv
-- 不支持其他)。其他(如@Qrrbrbirlbel)更喜欢第一种方法。