62147


ソート済みのTSVを読み込んで、keys番目の列を使って重複行を判定し、重複を除いて残った行だけを出力する予定のrustプログラムです（`uniq`コマンドと似た動作をするはずです）。  
コンパイルエラーの原因がわかりません。

[code]

    use std::io;
    use itertools::Itertools;
    
    
    fn main() {
        let stdin = io::stdin();
        let mut reader = csv::ReaderBuilder::new()
            .delimiter(b'\t')
            .has_headers(false)
            .trim(csv::Trim::All)
            .from_reader(stdin);
    
        let keys = vec![1, 2];
    
        // case 1 コンパイルできない
        reader.records()
            .map(|r| {
                (keys.iter().map(|&k| r.expect("row").iter().collect::<Vec<&str>>()[k]).collect::<Vec<_>>(), r)
            })
            .dedup_by(|x, y| x.0 == y.0)
            .map(|(key, value)| value)
            .for_each(|x| println!("{:?}", x));
    
        // case 2 動く
        reader.records()
            .map(|r| r.expect("row"))
            .dedup_by(|x, y| {
                keys.iter().map(|&k| x.get(k).unwrap()).collect::<Vec<_>>() == keys.iter().map(|&k| y.get(k).unwrap()).collect::<Vec<_>>()
            })
            .for_each(|x| println!("{:?}", x));
    }
    
[/code]

プログラム中のコメントにあるcase 2のほうは予想通りに動きます。case 1も同じ動作をすると思ったのですが、コンパイルができず、以下のエラーが出ます。

[code]

    $ cargo build
       Compiling dedupnande v0.1.0 (/home/xxxx/code/rust/dedupnande)
    error[E0599]: no method named `map` found for type `itertools::adaptors::DedupBy<std::iter::Map<csv::reader::StringRecordsIter<'_, std::io::Stdin>, [closure@src/main.rs:17:14: 19:10 keys:_]>, [closure@src/main.rs:20:19: 20:36]>` in the current scope
      --> src/main.rs:21:10
       |
    21 |         .map(|(key, value)| value)
       |          ^^^ method not found in `itertools::adaptors::DedupBy<std::iter::Map<csv::reader::StringRecordsIter<'_, std::io::Stdin>, [closure@src/main.rs:17:14: 19:10 keys:_]>, [closure@src/main.rs:20:19: 20:36]>`
       |
       = note: the method `map` exists but the following trait bounds were not satisfied:
               `&mut itertools::adaptors::DedupBy<std::iter::Map<csv::reader::StringRecordsIter<'_, std::io::Stdin>, [closure@src/main.rs:17:14: 19:10 keys:_]>, [closure@src/main.rs:20:19: 20:36]> : std::iter::Iterator`
               `itertools::adaptors::DedupBy<std::iter::Map<csv::reader::StringRecordsIter<'_, std::io::Stdin>, [closure@src/main.rs:17:14: 19:10 keys:_]>, [closure@src/main.rs:20:19: 20:36]> : std::iter::Iterator`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0599`.
    error: could not compile `dedupnande`.
    
    To learn more, run the command again with --verbose.
    
[/code]

`map`が`&mut
DedupBy<...>`にしか実装されていないというエラーみたいですが、意味がわかりません。DedupBy構造体はIteratorトレイトを実装しているんじゃないんですか……？

実行環境：

[code]

    [package]
    (...)
    edition = "2018"
    
    [dependencies]
    csv = "1.1"
    itertools = "0.8.2"
    
[/code]

[code]

    $ cargo --version
    cargo 1.40.0 (bc8e4c8be 2019-11-22)
    $ rustc --version
    rustc 1.40.0 (73528e339 2019-12-16)
    
[/code]


CC BY-SA 4.0
2020-01-10T17:24:45.000
62145
2020-01-10T18:15:40.583
37406
question
rust
Rustのコンパイルエラー（no method named `map` found for type ...）の原因


こんにちは。

ちょっとこれは罠ですね。 `DedupBy` は `Iterator` トレイトを実装していますが、条件付きです。  
ベースとなるイテレータのアイテムが `PartialEq` を実装しているときのみです。

<https://docs.rs/itertools/0.8.2/itertools/structs/struct.DedupBy.html#impl-
Iterator>

そして `reader.records()` のアイテムは `Result<StringRecord, Error>`
[なのです](https://docs.rs/csv/1.1.2/csv/struct.StringRecordsIter.html#impl-
Iterator)が、これは `Error` が `PartialEq` を実装していないため `PartialEq` ではありません。

<https://docs.rs/csv/1.1.2/csv/struct.Error.html>

なので下記のようにcase 1でも `Result::expect` を呼んで `Error`
を持たないように変形してあげればコンパイルが通るようになります。

[code]

        reader
            .records()
            .map(|r| {
                // rのResultを剥がしておく
                let r = r.expect("row");
                (
                    keys.iter()
                        .map(|&k| r.iter().collect::<Vec<&str>>()[k].to_string())
                        .collect::<Vec<_>>(),
                    r,
                )
            })
            .dedup_by(|x, y| x.0 == y.0)
            .map(|(_, value)| value)
            .for_each(|x| println!("{:?}", x));
    
[/code]


CC BY-SA 4.0
2020-01-10T18:15:40.583
62147
2020-01-10T18:15:40.583
22816
62145
answer