質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

405閲覧

structopt, clap のいずれの "validator" としても使える関数の定義方法

tomlla_92

総合スコア11

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2022/06/11 10:41

structopt の validator として指定する関数は
fn f(v: String) -> Result<...>
である必要があります。
一方、clapのvalidatorは
fn f(v: &str) -> Result<...>
である必要があります。

引数部分の型が違うので AsRef<str> を受け取る関数を作れば、両方のvalidatorとして使えるかと思いした。

しかし、clap側のインターフェースにはライフタイムに関して問題が置きます。
Higher-Order Trait Bound によるライフタイム指定が必要なのかもしれませんが、なかなかうまくいきません。
(そもそも私は Higher-Order Trait Boundに関する詳しくありません。)

以下のコードの structopt, clap 両方の validatorとして使える関数を用意したい場合、以下のコードの validator_for_general をどのように定義すればよいでしょうか?

rust

1use clap::Parser; 2use std::path::PathBuf; 3use structopt::StructOpt; 4 5fn existing_file(pathbuf: PathBuf) -> Result<(), String> { 6 if pathbuf.is_file() { 7 Ok(()) 8 } else { 9 Err(format!("No such file {:?})", pathbuf)) 10 } 11} 12 13pub fn validator_for_general<P>(filepath: P) -> Result<(), String> 14where 15 P: AsRef<str>, 16{ 17 let pathbuf = PathBuf::from(filepath.as_ref()); 18 existing_file(pathbuf) 19} 20 21#[derive(Parser)] 22struct ClapArgs { 23 #[clap(validator = validator_for_general)] 24 file1: PathBuf, 25} 26 27#[derive(StructOpt)] 28struct StructOptArgs { 29 #[structopt(validator = validator_for_general)] 30 file1: PathBuf, 31} 32 33fn main() {}
error[E0308]: mismatched types | 34 | #[clap(validator = validator_for_general)] | ^^^^^^^^^ lifetime mismatch | = note: expected type `<fn(&str) -> Result<(), std::string::String> {validator_for_general::<&str>} as FnOnce<(&str,)>>` found type `<fn(&str) -> Result<(), std::string::String> {validator_for_general::<&str>} as FnOnce<(&str,)>>` note: the required lifetime does not necessarily outlive the lifetime `'b` as defined here | 29 | #[derive(Parser)] | ^^^^^^ note: the lifetime requirement is introduced here | 1535 | F: FnMut(&str) -> Result<O, E> + Send + 'help, | ^^^^^^^^^^^^ = note: this error originates in the derive macro `Parser` (in Nightly builds, run with -Z macro-backtrace for more info) For more information about this error, try `rustc --explain E0308`. error: could not compile `argumnet_validator_general_interface` due to previous error

各種バージョン

  • rustc 1.60.0 (7737e0b5c 2022-04-04)
  • clap: 3.1.18 (features = ["derive"])
  • structopt: 0.3.26

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

少し試してみましたが、難しそうです。validatorは引数を渡してみて型が合えばOKという訳ではなく、トレイトで厳密に挙動を指定しています。

互換性のある型ではないのでどちらにでも使える関数は難しいでしょう。clap側としても互換性を担保できるのであればそうしているはずですし、あきらめるしかなさそうです。

承知かもしれませんが次善の策としてはstructopとclap両方のバリデータを用意して片方をもう片方のラッパとする、ですかね。

rust

1pub fn validator_for_clap(filepath: &str) -> Result<(), String> { 2 let pathbuf = PathBuf::from(filepath); 3 existing_file(pathbuf) 4} 5 6pub fn validator_for_structopt(filepath: String) -> Result<(), String> { 7 validator_for_clap(&filepath) 8}

事情があってのことかと存じますが、老婆心ながら指摘しておくとclap 2系のために作られたstructoptの機能はclap 3系で統合されており特別な事情がなければstructoptを使う理由はないのでstructoptの対応をやめるのも1つの解決策かもしれません。

投稿2022/09/13 00:40

blackenedgold

総合スコア468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問