我正在编写一个REPL(所以我在内部使用picocli来解析在应用程序中键入的命令,而不是解析命令行args),并且我有一个带有选项的命令,我希望这样做: / p>
> 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
知道未指定任何值?
答案 0 :(得分:1)
我实际上最终采取了不同的方法;这对我的应用程序能够直接分配给实际类型的字段很有帮助(因为我们正在开发一项功能,您可以在其中“发现”带有各种类型参数的命令,因此让该字段为实际类型可以使它反向查找更容易)。
所以我最终这样做了:
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,因为我们最终使用了双精度数),以表明该选项存在而没有任何值(这与根本不存在的值不同,在这种情况下它将为空。
然后按照您建议的在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。不过,这是一个小的牺牲。
我意识到这是一个不寻常的情况,但是支持这种选项(带布尔值0..n的非布尔值)而无需诉诸特殊值可能会很好。也许可以指定另一个字段作为指示该选项是否存在的布尔值。然后,也将不需要自定义转换器,并且可能仍可以指定默认值(即,在这种情况下,Double字段将被设置为默认值,但是如果不存在该选项,则对应的布尔字段将为假,因此应用程序将知道不使用Double的值。
答案 1 :(得分:0)
这当然是做到这一点的一种方法。请记住,setter方法可能会多次调用:一次重置默认值,然后每次在命令行上匹配该选项时再次调用。
另一种方法是将字段类型更改为String
,在字段上放置@Option
批注,然后从您的{中调用此逻辑(在上面的setValue
方法中) {1}}或run
方法。