1

我正在编写一个 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

4

2 回答 2

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);
            }
        }
    }       
}

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

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

于 2018-09-21T12:59:27.533 回答
0

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

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

于 2018-09-21T12:39:12.887 回答