Picocli:使用可选值指定选项的最佳方法,该值在未指定值时打印当前值



我正在编写一个 REPL(所以我在内部使用 picocli 来解析应用程序中键入的命令,而不是解析命令行参数(,我有一个带有选项的命令,我想像这样运行:

> cmd --myopt
Myopt value = 5
> cmd --myopt 4
> cmd --myopt
Myopt value = 4

也就是说,如果指定选项时没有值,则打印参数的当前值,但如果指定值,则设置该值。我想这样做:

int value = 1; // default
@Option(names = {"-e", "--epsilon"}, arity = "0..1",
description = "Acceptable values: [0, 1] default: ${DEFAULT-VALUE}")
void setValue(String strValue) {
if (strValue == "") {
printValue();
} else {
try {
value = Integer.parseInt(strValue);
// validate value
} catch (NumberFormatException e) {
// print help for this option
}
}
}

这是最好的方法吗?有没有另一种方法可以捕获描述中的默认值,同时仍然允许setValue知道未指定任何值?

(另见 https://github.com/remkop/picocli/issues/490(

实际上,我最终采用了不同的方法;对于我的应用程序来说,能够直接分配给实际类型的字段很有帮助(因为我们正在开发一项功能,您可以在其中"发现"接受各种类型的参数的命令,因此将字段设置为实际类型使这种反向查找更容易(。

所以我最终这样做了:

static class DoubleConverter implements ITypeConverter<Double> {
public Double convert(String value) throws Exception {
if(value.isEmpty()) return Double.NaN; // this is a special value that indicates the option was present without a value
return Double.valueOf(value);
}
}
@Option(names = {"-e", "--epsilon"}, arity="0..1", description="Acceptable values: [0, 1] default: 0.1", converter=DoubleConverter.class)
Double epsilon;

基本上,我使用转换器来存储一个特殊值(在本例中为 NaN,因为我们最终使用了双精度值(来指示该选项在没有值的情况下存在(这与它根本不存在不同,在这种情况下它将为 null(。

然后,按照您的建议在run()方法中执行验证和其他行为:

@Override
public void run() {
// null indicates the option was not present, so do nothing
if(epsilon != null) {
// NaN indicates the option was present but with no value, which means we should print the current value
if(epsilon.equals(Double.NaN)) {
// print current value from the application
printEpsilonValue();
}
else {
// validate value
if(epsilon < 0.0 || epsilon > 1.0) {
throw new ParameterException(spec.commandLine(), "Invalid parameter value");
} else {
// set the value in the application
setEpsilonValue(episilon);
}
}
}       
}

我无法使用变量在描述中指定默认值,因为在这种情况下,实际默认值需要为 null。不过,这只是一个小小的牺牲。

我意识到这是一种不寻常的情况,但是支持这种选项(arity 为 0..n 的非布尔值(而不需要求助于特殊值可能会很好。也许能够指定另一个字段作为指示该选项是否存在的布尔值。这样也就不需要自定义转换器了,并且可能仍然可以指定默认值(即,在这种情况下,Double 字段将设置为默认值,但如果该选项不存在,则相应的布尔字段将为 false,因此应用程序将知道不使用 Double 的值(。

这当然是一种方法。请记住,setter 方法可能会被调用多次:一次用于重置默认值,然后每次在命令行上匹配该选项时再次调用。

另一种方法是将字段类型更改为String,将@Option注释放在字段上,然后从runcall方法调用此逻辑(即在上面的setValue方法中(。

最新更新