gpt4 book ai didi

rust - 有没有办法使用 docopt 从命令行传递 u8 的向量?

转载 作者:行者123 更新时间:2023-11-29 08:27:08 25 4
gpt4 key购买 nike

有没有办法让用户提示输入括号内的字节并用逗号或类似的东西分隔?

./main bytes [0, 1, 2, 3, 4, 5]

我设法让它看起来像这样:

./main bytes 0 1 2 3 4 5

这是我的代码:

extern crate docopt;
#[macro_use]
extern crate serde_derive;

use docopt::Docopt;

const USAGE: &'static str = "
Puzzle Solver.

Usage:
puzzle_solver string <text>
puzzle_solver bytes [<bin>...]
puzzle_solver (-h | --help)
puzzle_solver --version

Options:
-h --help Show this screen.
--version Show version.
";

#[derive(Debug, Deserialize)]
struct Args {
cmd_string: bool,
arg_text: Option<String>,
cmd_bytes: bool,
arg_bin: Option<Vec<u8>>,
}

fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit());

println!("ARGS: {:?}", args);
}

最佳答案

这是可能的,但你必须实现Deserialize手工制作。

Vec<u8>已经实现 Deserialize ,并且该实现不知道包含逗号分隔的括号列表的字符串, docopt::Deserializer 也不知道。 ,因为在命令行上传递列表的正常方式是逐个元素。因此,您必须创建一个新类型,该类型将从您想要的格式反序列化。

当然你也可以实现Deref<Target = Vec<u8>>DerefMut对于 Bytes , 如果你想把它当作 Vec<u8> . Some people might consider this a slight misuse of Deref ,但在这种情况下可能没问题。

extern crate docopt;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use docopt::Docopt;
use serde::de;
use std::fmt;

const USAGE: &'static str = "
Puzzle Solver.

Usage:
puzzle_solver string <text>
puzzle_solver bytes <bin>
puzzle_solver (-h | --help)
puzzle_solver --version

Options:
-h --help Show this screen.
--version Show version.
";

#[derive(Debug, Deserialize)]
struct Args {
cmd_string: bool,
arg_text: Option<String>,
cmd_bytes: bool,
arg_bin: Option<Bytes>,
}

#[derive(Debug)]
struct Bytes(Vec<u8>);

impl<'de> de::Deserialize<'de> for Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct BytesVisitor;

impl<'de> de::Visitor<'de> for BytesVisitor {
type Value = Bytes;

fn expecting(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(formatter, "a bracketed, comma-delimited string")
}

fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = if v.starts_with('[') && v.ends_with(']') {
&v[1..v.len() - 1]
} else {
return Err(E::custom(format!("expected a bracketed list, got {:?}", v)));
};
let values: Result<Vec<u8>, _> = v.split(",").map(|s| s.trim().parse()).collect();
Ok(Bytes(values.map_err(E::custom)?))
}
}

deserializer.deserialize_str(BytesVisitor)
}
}

Here it is in the playground.这些是我为使其正常工作所做的更改:

  1. 替换[<bin>...]<bin>所以 docopt 将知道要查找单个事物而不是一系列……事物。 (如果您不这样做,docopt 实际上只会抛出一个空字符串。)
  2. 介绍新类型Bytes包装 Vec<u8> .
  3. Implement serde::de::Deserialize 对于 Bytes .这需要创建一个实现 serde::de::Visitor 的结构trait,将分离字符串的代码放在其 visit_str 中方法,并将访问者传递给 deserialize_str ,它告诉 Deserializer期待一个字符串并将其传递给访问者的 visit_str .

直到快完成我才意识到,但你可以实现 visit_seq相反,让它解析 bytes [1, 2, 3] (不引用列表)。但我不会,因为这违背了命令行约定;如果您无论如何都使用 shell 来拆分参数,那么您应该一路走下去,只接受 bytes 1 2 3 .

关于rust - 有没有办法使用 docopt 从命令行传递 u8 的向量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47823800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com