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

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

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

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

Q&A

解決済

2回答

2239閲覧

参照の引数を持つ関数を別の関数に渡したい

namuyan

総合スコア76

Rust

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

0グッド

1クリップ

投稿2020/06/03 05:45

編集2020/06/05 05:25

where句を用いて関数型をFに指定して、またargsの一部をTに指定して関数に渡したいです。

rust

1pub fn func_a<T: AsRef<[u8]>>(input: T) -> Vec<u8> { 2 unimplemented!() 3} 4 5pub fn func_b<F, T>(&self, func: F) 6where 7 T: AsRef<[u8]>, 8 F: Fn(T) -> Vec<u8>, 9{ 10 let input: Vec<u8> = vec![0, 1, 2, 3]; 11 let output = fnc(input.as_ref()); 12 unimplemented!() 13}

関数func_aを関数func_bargとして渡したいです。だいたいwhere句は上記のような例になると予想しますがコンパイルが通りません。下記のようなエラーが出現します。

error

1error[E0308]: mismatched types 2 --> src\named.rs:67:30 3 | 457 | fn func_b<F, T: AsRef<[u8]>>(&self, fnc: F) -> (Vec<u8>, u32) 5 | - this type parameter 6... 767 | let output = fnc(input.as_ref()); 8 | ^^^^^^^^^^^^^^ expected type parameter `T`, found `&[u8]` 9 | 10 = note: expected type parameter `T` 11 found reference `&[u8]` 12 = help: type parameters must be constrained to match other types 13 = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

func_aは外部から取得するのでfunc_bを変える事になります。

この問題はどのように解決をすればいいでしょうか?
何かわかる方は回答の方をよろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは。
元のコードがお困りの箇所以外でもエラーがある(&selffuncfnc など)ので回答が難しいのですが、以下のコードであればコンパイルが通ります。

rust

1pub fn func_a<T: AsRef<[u8]>>(input: T) -> Vec<u8> { 2 unimplemented!() 3} 4 5pub fn func_b<F>(func: F) 6where 7 F: Fn(&[u8]) -> Vec<u8>, 8{ 9 let input: Vec<u8> = vec![0, 1, 2, 3]; 10 let output = func(input.as_ref()); 11 unimplemented!() 12}

play ground

恐らく、 func_a がジェネリクスなので func_b でもジェネリクスっぽく指定しようとしたのだと思います。恐らくお気付きかと思いますが、残念ながらRustではジェネリクス関数をジェネリクスとして受け取ることはできません。やるとしたら以下の2つのうち、どちらかになります。

  1. ジェネリクス関数を受け取る関数(ここでは func_b のこと)も、ジェネリクスにする
  2. ジェネリクスではなく固定の型を受け取る関数として受け取る

1の方法は受け取る関数(func_b)の外部からデータを与える場合に向いており、2の方法は関数内部でデータを用意する場合に向いています。
今回提示されたコードは関数内部でデータを用意していますが、型付けが1の方法だったのでエラーになっていました。そこで2の方法で型を書き直してエラーを解消しました。

この回答と他の回答との差分ですが、F のトレイト境界にライフタイム注釈があるかどうかの違いです。
F: Fn(&[u8]) -> Vec<u8> とライフタイム注釈なしでトレイト境界を書いた場合は F: for<'a> Fn(&'a [u8]) -> Vec<u8> と書いたのと同じ意味になります。これは func_b のジェネリクスパラメータに 'a を書くのとは異なる意味を持ちます(こちらの方がより自然な挙動をします)。このあたりはややこしいのでさらなる情報が欲しい場合はRustnomiconの高階トレイト境界を参照してみて下さい。

投稿2020/06/04 05:21

blackenedgold

総合スコア468

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

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

namuyan

2020/06/05 05:28

通りましたね!クロージャの入力と出力の型を明示しない癖が上手くいったのかもしれませんね。
guest

0

funcの入力の型が決まっているならそれを書くことになるのではないかと思います。

あと、AsRef<T>as_ref() を呼んだら &T になるものであって、渡す側で as_ref() する必要はありません。

具体的なコードは以下にあります。
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=37925ddc9137be4f07653756ccebe1ab

投稿2020/06/03 09:06

Toru3

総合スコア32

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

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

namuyan

2020/06/03 10:26

ありがとうございます。入力には`Fn(&[u8]) -> Vec<u8>`を想定しましたがlifetimeの関係でエラーになります。どのように書けばよろしいでしょうか?
namuyan

2020/06/04 04:01

関数内部に修飾子をいれられるのですね、でも修飾されるとすぐに解放されて"does not live long enough"とエラー出されます。あとfunc内部がわからないからブロックの終わりまで借用される事になる?というのも、今のRustの言語仕様の限界..という感じがしますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問