[解決済み] Iterator(またはその他の trait)を返す正しい方法は何ですか?
質問
以下のRustコードは問題なくコンパイル・実行されます。
fn main() {
let text = "abc";
println!("{}", text.split(' ').take(2).count());
}
その後、次のようなことをやってみたのですが......コンパイルできませんでした。
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
fn to_words(text: &str) -> &Iterator<Item = &str> {
&(text.split(' '))
}
主な問題は、関数の戻り値の型がわからないことです。
to_words()
があるはずです。コンパイラはこう言っています。
error[E0599]: no method named `count` found for type `std::iter::Take<std::iter::Iterator<Item=&str>>` in the current scope
--> src/main.rs:3:43
|
3 | println!("{}", to_words(text).take(2).count());
| ^^^^^
|
= note: the method `count` exists but the following trait bounds were not satisfied:
`std::iter::Iterator<Item=&str> : std::marker::Sized`
`std::iter::Take<std::iter::Iterator<Item=&str>> : std::iter::Iterator`
これを実行するための正しいコードは何でしょう? ...そして、私の知識のギャップはどこにあるのでしょう?
どのように解決するのですか?
コンパイラにガイドさせるのが便利なんだ。
fn to_words(text: &str) { // Note no return type
text.split(' ')
}
コンパイルすると
error[E0308]: mismatched types
--> src/lib.rs:5:5
|
5 | text.split(' ')
| ^^^^^^^^^^^^^^^ expected (), found struct `std::str::Split`
|
= note: expected type `()`
found type `std::str::Split<'_, char>`
help: try adding a semicolon
|
5 | text.split(' ');
| ^
help: try adding a return type
|
3 | fn to_words(text: &str) -> std::str::Split<'_, char> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
コンパイラの提案に従って、それを私の戻り値としてコピーペーストしています(少し整理して)。
use std::str;
fn to_words(text: &str) -> str::Split<'_, char> {
text.split(' ')
}
のような trait を返すことができないのが問題です。
Iterator
なぜなら、traitはサイズを持たないからです。つまり、Rustはその型にどれだけの領域を確保すればいいのかわからないのです。あなたは
は、ローカル変数への参照を返すこともできません。
を返します。
&dyn Iterator
は非推奨です。
インプリメンタル特性
Rust 1.26以降では、このように
impl trait
:
fn to_words<'a>(text: &'a str) -> impl Iterator<Item = &'a str> {
text.split(' ')
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
これの使い方には制限があります。単一の型しか返すことができず(条件付きは不可!)、自由関数か固有の実装で使用しなければなりません。
ボックス型
多少効率が悪くなっても構わないのであれば、このように
Box<dyn Iterator>
:
fn to_words<'a>(text: &'a str) -> Box<dyn Iterator<Item = &'a str> + 'a> {
Box::new(text.split(' '))
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
を可能にする主要なオプションです。 ダイナミックディスパッチ . つまり、コードの正確な実装は、コンパイル時ではなく、実行時に決定されます。つまり、ある条件に基づいて複数の具象型イテレータを返す必要がある場合に適している。
ニュータイプ
use std::str;
struct Wrapper<'a>(str::Split<'a, char>);
impl<'a> Iterator for Wrapper<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
self.0.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
fn to_words(text: &str) -> Wrapper<'_> {
Wrapper(text.split(' '))
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
タイプエイリアス
として reemさんご指摘の
use std::str;
type MyIter<'a> = str::Split<'a, char>;
fn to_words(text: &str) -> MyIter<'_> {
text.split(' ')
}
fn main() {
let text = "word1 word2 word3";
println!("{}", to_words(text).take(2).count());
}
クロージャの扱い
いつ
impl Trait
が使用できない場合、クロージャは事態をより複雑にします。クロージャは無名型を作成し、これらは戻り値の型に名前を付けることができません。
fn odd_numbers() -> () {
(0..100).filter(|&v| v % 2 != 0)
}
found type `std::iter::Filter<std::ops::Range<{integer}>, [closure@src/lib.rs:4:21: 4:36]>`
場合によっては、これらのクロージャを関数に置き換えて、名前を付けることができます。
fn odd_numbers() -> () {
fn f(&v: &i32) -> bool {
v % 2 != 0
}
(0..100).filter(f as fn(v: &i32) -> bool)
}
found type `std::iter::Filter<std::ops::Range<i32>, for<'r> fn(&'r i32) -> bool>`
そして、上記のアドバイスに従って
use std::{iter::Filter, ops::Range};
type Odds = Filter<Range<i32>, fn(&i32) -> bool>;
fn odd_numbers() -> Odds {
fn f(&v: &i32) -> bool {
v % 2 != 0
}
(0..100).filter(f as fn(v: &i32) -> bool)
}
条件分岐の処理
イテレータを条件付きで選択する必要がある場合、以下を参照してください。 複数のイテレータのうち1つを条件付きで反復処理する .
関連
-
[解決済み] rustupでインストールしたRustをアンインストールするには?
-
[解決済み] Rust の `String` と `str` の違いは何ですか?
-
[解決済み] なぜRustコンパイラは、2つのミュータブル参照がエイリアスできないと仮定してコードを最適化しないのですか?
-
[解決済み】ライブラリとバイナリの両方を持つRustパッケージ?
-
[解決済み] このクエスチョンマークの演算子は何についてですか?
-
[解決済み] Cargoで複数のバイナリをビルドするにはどうしたらいいですか?
-
[解決済み] Rust の 128 ビット整数 `i128` は 64 ビットシステムでどのように動作するのでしょうか?
-
[解決済み】iterとinto_iterの違いは何ですか?
-
[解決済み] Rust構造体の変数を初期化する、より速い/より短い方法はありますか?
-
[解決済み] アポストロフィが1つ付いているラストタイプは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] rustupでインストールしたRustをアンインストールするには?
-
[解決済み] RustのRc::clone(&rc)とrc.clone()は何か違いがあるのでしょうか?また、それによるコンパイルの最適化はあるのでしょうか?
-
[解決済み] Rustのユニットテストでprintln! が動作しないのはなぜ?
-
[解決済み】Rustの実行ファイルはなぜこんなに巨大なのですか?
-
[解決済み】Rustで文字列を分割する方法は?
-
[解決済み] このクエスチョンマークの演算子は何についてですか?
-
[解決済み] バイトのベクター(u8)を文字列に変換するには?
-
[解決済み] クロージャがFn、FnMut、FnOnceを実装するのはどんなとき?
-
[解決済み] カスタムステップで範囲を反復処理するには?
-
[解決済み] Stringを&'static strに変換する方法