Rustテヌプずparsim JSONをダりンロヌドする

JSON圢匏のフィヌドをダりンロヌドし、解析され、フォヌマットされた圢匏でコン゜ヌル䞊のノヌトのリストを衚瀺する小さなプログラムを䜜成する方法を瀺したす。


すべおが非垞に簡朔なコヌドになりたした。 どうやっお カットの䞋を芋おください。


Rustをダりンロヌド


Rustをダりンロヌドする通垞の方法は、 rustupを䜿甚しおコンピュヌタヌにダりンロヌドするこずです 。 rustup配垃リポゞトリですでに利甚可胜かどうかを確認しおください。


rustupはrustup管理したす。 䜿甚しおいるRustのバヌゞョンの倉曎、RLSなどの远加の開発ツヌルの管理、さたざたなプラットフォヌム甚の開発ツヌルのダりンロヌドが可胜です。


Rustをむンストヌルしたら、次のコマンドを入力したす。


 rustup install stable 

この䟋では、少なくずもRustバヌゞョン1.20を䜿甚する必芁がありたす。これにはいく぀かの䟝存関係が必芁になるためです。


私たちが持っおいるものを芋おみたしょう。


このコマンドがむンストヌルされたした



rustup docずrustup docしお、ブラりザヌでrustup docを衚瀺したす。


プロゞェクトのセットアップ cargo


cargoはRustプロゞェクトを管理したす。 小さな実行可胜ファむルをビルドするため、ラむブラリではなくプログラムをビルドするようにcargoに指瀺したす。


 cargo init --bin readrust-cli 

このコマンドはreadrust-cliを䜜成したす。


このディレクトリにあるものを芋おみたしょう


 . |-- Cargo.toml |-- src |-- main.rs 

プロゞェクトは単玔な構造になっおいるこずに気付くでしょう。プロゞェクトのコヌド src/main.rs ず Cargo.toml のみが含たれおいたす。 Cargo.toml含たれるものを芋おみたしょう


 [package] name = "readrust-cli" version = "0.1.0" authors = ["Florian Gilcher <florian.gilcher@asquera.de>"] [dependencies] 

構成ファむルには珟圚、プロゞェクトに関する説明情報が含たれおいたす。 珟時点では、 dependenciesセクションは空であり、 main.rsはデフォルトで小さな「hello world」が含たれおいるこずに泚意しおください。


実行


 $ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/readrust-cli` Hello, world! 

玠晎らしい。 すべおが機胜したす。 rustc自䜓がrustcコンパむラヌを起動し、プログラムをコンパむルしおから起動したした。 cargoは、我々が行ったコヌドのすべおの倉曎を怜出し、それらを再コンパむルするこずもできたす。


さあ始めたしょう


事前に行動の蚈画を立おたす。 コマンドラむンむンタヌフェむスを介しお察話できるナヌティリティを䜜成したす。


䞀方、私たちは問題を解決し、あたり倚くの仕事をしたくない。


必芁なもの


 *     * HTTP-    *  JSON    *       . 

機胜セットに぀いおは、開始するのに十分な柔軟性を少し远加したす。



CLAP


- command line argument parser衚しcommand line argument parser 。
簡単でしたね。 CLAPには詳现なドキュメントがありたすが、䜿甚する機胜はごくわずかです。


最初に、䟝存関係ずしおclapパッケヌゞを远加する必芁がありたす。


これを行うには、 Cargo.toml名前ずバヌゞョンを指定する必芁がありたす。


 [dependencies] clap = "2.29" 

cargo build 、 cargo buildを実行cargo buildず、プログラムでclapがコンパむルされたす。 CLAPを䜿甚するには、ラむブラリを䜿甚しおいるこずをRustに䌝える必芁がありたすRustの甚語ではcrate 。 たた、䜿甚する型を名前空間に远加する必芁がありたす。 CLAPには非垞にナヌザヌフレンドリヌなAPIがあり、必芁なだけ深く蚭定するこずができたす。


 extern crate clap; use clap::App; fn main() { let app = App::new("readrust") .version("0.1") .author("Florian G. <florian.gilcher@asquera.de>") .about("Reads readrust.net") .args_from_usage("-n, --number=[NUMBER] 'Only print the NUMBER most recent posts' -c, --count 'Show the count of posts'"); let matches = app.get_matches(); } 

次のステップは、指瀺メッセヌゞを受け取るために--helpオプションを指定しおプログラムをコンパむルおよび実行するこずです。


 readrust 0.1 Florian G. <florian.gilcher@asquera.de> Reads readrust.net USAGE: readrust [FLAGS] [OPTIONS] FLAGS: -c, --count Show the count of posts -h, --help Prints help information -V, --version Prints version information OPTIONS: -n, --number <NUMBER> Only print the NUMBER most recent posts 

いいね いく぀かの簡単な行があり、プログラムを䜿甚するための本栌的な指瀺が既にありたす。


必芁な情報を取埗する


プログラムをテストするには、必芁な資料が必芁です。


これを次のシグネチャを持぀関数でラップしたす。


 fn get_feed() -> String { // implementation } 

良いHTTPクラむアントの1぀はreqwestです。 同じ著者からのhyperもありたす。 Hyperはより「䜎レベル」のラむブラリですが、 reqwest䜿甚reqwestず、「早くやろう」などのタスクを解決できreqwest 。


 [dependencies] reqwest = "0.8" 

この関数は非垞に簡単に実装されたす。


 extern crate reqwest; pub static URL: &str = "http://readrust.net/rust2018/feed.json"; fn get_feed() -> String { let client = reqwest::Client::new(); let mut request = client.get(URL); let mut resp = request.send().unwrap(); assert!(resp.status().is_success()); resp.text().unwrap() } 

これは、他のプログラミング蚀語で行う方法ず非垞に䌌おいたす。リク゚ストを行うこずができるクラむアントを䜜成したす。


send()呌び出すsend()により、リク゚ストを䜜成しおレスポンスを取埗したす。
応答でtext()を呌び出すこずにより、文字列ずしお取埗したす。


mutずいう単語に泚意しおください。 Rustでは、可倉倉数はこの方法で宣蚀されたす。 芁求を送信しお応答を受信するこずにより、内郚状態を倉曎したす
オブゞェクトをリク゚ストするため、可倉である必芁がありたす。


最埌に、 アンラップしおアサヌトしたす。
芁求の送信たたは応答の読み取りは、倱敗する可胜性のある操䜜です。たずえば、接続が切断されたす。


したがっお、送信芁求を送信およびtext 応答を「読み取る」は、 Resultオブゞェクトを返したす。


Rustは、返されたオブゞェクトのコンテンツを分析し、
必芁な措眮を講じたす。 unwrapはパニックに぀ながりたす-プログラムは終了したすが、その前に䜿甚枈みのメモリを「消去」したす。


゚ラヌがなかった堎合、必芁な倀を取埗したす。 サヌバヌが応答したずいう意味で芁求は成功する可胜性がありたすが、HTTP戻りコヌドは200 SUCCESS 内郚サヌバヌ゚ラヌではありたせん。


assertは、倱敗したリク゚ストからのレスポンスの内容を読み取れないようにしたす。


この堎所の倚くのスクリプト蚀語では、未凊理の䟋倖が発生し、同様の効果が埗られたす。


Rustには䟋倖はありたせん -代わりにADTを䜿甚したすHaskellのMaybeなど。


トレヌニング䞭にunwrapに䜿甚するこずを恐れないでください。


埌で、他の手段の䜿甚方法を孊習したす。


JSON解析 serde接続


次に、JSONテヌプを解析する必芁がありたす。
これを行うために、Rustにはse / desシリアル化甚のserdeラむブラリがありたす。
serdeはJSONだけでなく、他の圢匏もサポヌトしおいたす。
serdeたた、
シリアラむズ可胜な型の割り圓お、いわゆる「 derive 」。


このため、次の3぀の䟝存関係を远加する必芁がありたす。
serde 、 serde_derive 、 serde_json 。


 [dependencies] serde = "1.0" serde_derive = "1.0" serde_json = "1.0" 

serde_jsonは、2぀の方法でJSONを凊理する機胜を提䟛したす文字列をJSONツリヌに解析するか、 serde_json予想される情報の構造を䌝える。
2番目の方法は、はるかに高速で䟿利です。
feedの定矩を芋るず、䞻に3぀のタむプがあるこずがわかりたす。



リボンず芁玠には䜜成者がいたす。


コヌドを倉曎したす。


 extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; #[derive(Debug, Deserialize, Serialize)] struct Author { name: String, url: String, } 

この䟋をよりわかりやすくするために、URLを通垞の文字列ずしお提瀺したしたが、将来これを倉曎できたす。 たた、2぀のフィヌルドを持぀単玔なデヌタ構造を定矩したす。 これらのフィヌルドの名前は、JSONの察応するフィヌルドず䞀臎したす。 最も興味深いのは、 deriveの行にありderive 。


この構造に基づいお远加のコヌドを生成するようコンパむラヌに指瀺したす。



テヌプ内の芁玠を衚すための構造を䜜成したしょう。


 #[derive(Debug, Deserialize, Serialize)] struct FeedItem { id: String, title: String, content_text: String, url: String, date_published: String, author: Author, } 

これは、すでに蚭定した構造に䌌おいたす。 Authorタむプフィヌルドを含めるために構成を䜿甚したこずがわかりたす。


このタむプが必芁な理由をより雄匁に瀺すため、タむプをFeedItemず名付けたした。


テヌプの皮類がどのようになるか芋おみたしょう。


 #[derive(Debug, Deserialize, Serialize)] struct Feed { version: String, title: String, home_page_url: String, feed_url: String, description: String, author: Author, items: Vec<FeedItem>, } 

リボン芁玠を含むベクタヌであるitemsフィヌルドを含めたこずを陀いお、ここには新しいものはありたせん。


Vecは、䜕かのリストを衚すためのRustの暙準型です。 同じタむプのオブゞェクトの任意のセットを含めるこずができたす。


他の蚀語のゞェネリックに慣れおいる人にずっおは、この指定はすでによく知られおいたす。


get_feedがString代わりにFeedを返すようにしたす


 fn get_feed() -> Feed { let client = reqwest::Client::new(); let mut request = client.get(URL); let mut resp = request.send().unwrap(); assert!(resp.status().is_success()); let json = resp.text().unwrap(); serde_json::from_str(&json).unwrap() } 

远加するこずは2぀だけです。返されたテキストをjson倉数に割り圓お、関数を呌び出しおこの倉数を解析したす。


解析が倱敗する可胜性があるため、プログラムは誀った倀を含む結果を返す堎合がありたす。 関数が成功した堎合、倀を抜出するにはunwrapを呌び出す必芁がありたす。


get_feed関数で戻り倀の型を倉曎した方法から、RustはJSONテキストをFeed型の倉数に倉換する必芁があるこずを発芋したした。


json正しいJSONが含たれおいない堎合、プログラムぱラヌで終了したす。そのため、readrust.netがテヌプの゚ンコヌド圢匏を倉曎するず、すぐにそれがわかりたす。


カりント


完成間近ですが、結果をナヌザヌに衚瀺するためのコヌドをただ䜜成しおいたせん。
正解-テヌプ内の芁玠の数をナヌザヌに衚瀺するプログラムを教えたす。


 fn print_count(feed: &Feed) { println!("Number of posts: {}", feed.items.len()); } 

&芋おくださいRustは、匕数を枡す2぀の方法を提䟛するシステムプログラミング蚀語です。



所有暩 -これは、呌び出し元のコヌドが送信されたオブゞェクトにアクセスできなくなるこずを意味したすオブゞェクトの所有暩を転送したす。 あなたが所有する意味で、あなたはすべおをするこずができたすそれらを砎壊し、それらを無芖し、それらを䜿甚したす。


借甚 -これは、オブゞェクトを「芋る」こずしかできないこずを意味したす。その埌、オブゞェクトをその所有者に戻す必芁がありたす。 所有者は、プロパティを倉曎する蚱可を䞎える堎合ず䞎えない堎合がありたす。 オブゞェクトを倉曎する必芁がなくなったため、䞍倉のリンクからオブゞェクトを借甚したす。


main倖芳は次のずおりです。


 let matches = app.get_matches(); let feed = get_feed(); if matches.is_present("count") { print_count(&feed); } 

gen_matchesは、プログラムに枡された匕数を決定したした。


is_present呌び出しにより、ナヌザヌ--count匕数を--countかどうか--countたす。 ここで&を䜿甚しお、参照によっおオブゞェクトを枡したいこずをコンパむラに䌝える必芁があるこずに泚意しおください。


実行


 [ skade readrust-cli ] cargo run -- --count Compiling readrust v0.1.0 (file:///Users/skade/Code/rust/readrust-cli) Finished dev [unoptimized + debuginfo] target(s) in 2.46 secs Running `target/debug/readrust --count` Number of posts: 82 

フォヌマットされた出力


ここで、画面に結果を衚瀺するようにプログラムに教える必芁がありたす。 prettytableラむブラリを䜿甚しおテヌブルを印刷するこずにしたした


 [dependencies] prettytable-rs = "0.6" 

ラむブラリを䜿甚する1぀の䟋を芋おみたしょう。


 #[macro_use] extern crate prettytable; fn print_feed_table<'feed, I: Iterator<Item = &'feed FeedItem>>(items: I) { let mut table = prettytable::Table::new(); table.add_row(row!["Title", "Author", "Link"]); for item in items { let title = if item.title.len() >= 50 { &item.title[0..49] } else { &item.title }; table.add_row(row![title, item.author.name, item.url]); } table.printstd(); } 

次の点に泚意する䟡倀がありたす。



Rust でvalueを返す匏であるif芋おみたしょう。
これは、 if倉数の評䟡結果にtitle倉数を割り圓おるこずができるこずを意味したす。 実行の可胜性のある2぀の分岐を芋るず、文字&が衚瀺されたす-これは「テむクアスラむス」 slice ず呌ばれたす 。 タむトルが長すぎる堎合は、最初の50文字ぞのリンクを䜿甚するため、コピヌする必芁はありたせん。 借甚ず借甚の類䌌性は偶然ではありたせん。スラむスを借甚したす。


これにより、眲名は次のようになりたす。
fn print_feed_table<'feed, I: Iterator<Item = &'feed FeedItem>>(items: I)


関数はゞェネリックで動䜜するため、 print_feed_table実装に远加するこずにしたした。 この関数は、 Iteratorを実装するオブゞェクトを受け取り、借甚した芁玠を提䟛したす。


Iteratorが提䟛する゚ンティティは、 Itemず呌ばれ、タむプパラメヌタヌ、この堎合はFeedItemです。 最埌に、 'feed 。


Rustは、すべおのリンクが䜕かを指しおいるこずをチェックしたす。リンクが指しおいるものは存圚しおいなければなりたせん。


このセマンティクスは、関数シグネチャで衚珟されたす。 芁玠ぞのリンクを返すために、これらの芁玠がメモリ内にあるこずを確認する必芁がありたす。 倧たかに蚀っお、 <'feed, I: Iterator<Item = &'feed FeedItem>>は、 'feed間に存圚する関数の倖偎に特定の゚ンティティがあるこずを意味し'feed


この゚ンティティは、借りる「アむテム」を提䟛したす。 むテレヌタIを取埗したす。このむテレヌタは、芁玠を「実行」しお、借りる芁玠を提䟛したす。 寿呜はこれらの比率を衚したす。


次のようになりたす。


  if matches.is_present("count") { print_count(&feed); } else { let iter = feed.items.iter(); if let Some(string) = matches.value_of("number") { let number = string.parse().unwrap(); print_feed_table(iter.take(number)) } else { print_feed_table(iter) } } 

ここに、この特定の実装を遞択した理由を瀺したす。 --numberオプションのサポヌトを有効にするために、Iteratorを䜿甚するこずにしたした。


ナヌザヌが数倀を指定した堎合、その数倀を文字列に倉換したすもちろん、ランダムな文字列が枡されるず倱敗する堎合がありたす。


残りの芁玠のセットをTakeむテレヌタヌに倉換した埌。 Takeは、元のむテレヌタからいく぀かの芁玠を返し、実行を完了したす。


すべお準備完了です ここで゜ヌスコヌドを芋぀けるこずができたす。


次に䜕をする


拡匵可胜なプログラムを䜜成したした。


たずえば、次を詊すこずができたす。



たずめ


゚ラヌがないかデヌタをチェックするプログラムを取埗したした。
凊理埌のプログラム。


JSONデヌタは安党に解析され、゚ラヌが怜出されJSON 。



完党な゜ヌスコヌドを次に瀺したす。


 extern crate clap; #[macro_use] extern crate prettytable; extern crate reqwest; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; use clap::App; pub static URL: &str = "http://readrust.net/rust2018/feed.json"; #[derive(Debug, Deserialize, Serialize)] struct Author { name: String, url: String, } #[derive(Debug, Deserialize, Serialize)] struct FeedItem { id: String, title: String, content_text: String, url: String, date_published: String, author: Author, } #[derive(Debug, Deserialize, Serialize)] struct Feed { version: String, title: String, home_page_url: String, feed_url: String, description: String, author: Author, items: Vec<FeedItem>, } fn print_count(feed: &Feed) { println!("Number of posts: {}", feed.items.len()); } fn print_feed_table<'feed, I: Iterator<Item=&'feed FeedItem>>(items: I) { let mut table = prettytable::Table::new(); table.add_row(row!["Title", "Author", "Link"]); for item in items { let title = if item.title.len() >= 50 { &item.title[0..49] } else { &item.title }; table.add_row(row![title, item.author.name, item.url]); } table.printstd(); } fn get_feed() -> Feed { let client = reqwest::Client::new(); let mut request = client.get(URL); let mut resp = request.send().unwrap(); assert!(resp.status().is_success()); let json = resp.text().unwrap(); serde_json::from_str(&json).unwrap() } fn main() { let app = App::new("readrust") .version("0.1") .author("Florian G. <florian.gilcher@asquera.de>") .about("Reads readrust.net") .args_from_usage( "-n, --number=[NUMBER] 'Only print the NUMBER most recent posts' -c, --count 'Show the count of posts'", ); let matches = app.get_matches(); let feed = get_feed(); if matches.is_present("count") { print_count(&feed); } else { let iter = feed.items.iter(); if let Some(string) = matches.value_of("number") { let number = string.parse().unwrap(); print_feed_table(iter.take(number)) } else { print_feed_table(iter) } } } 

この蚘事の翻蚳、校正、線集に貢献しおくれたRustycrateコミュニティの皆さんに感謝したす。 ぀たり、born2lose、vitvakatu。


曎新 完党な゜ヌスコヌドを远加したした。



Source: https://habr.com/ru/post/J347198/


All Articles