Charaken 技術系ブログ

技術系に関して学んだことや、気になったことを記事にしていく。

【Rust】がばがばRust独学 - 13. Functional Language Features - 1 Closures (2)

f:id:charaken:20191223210559p:plain

Rustの公式ドキュメントを通して、Rustを独学していく記事になります。(がば要素あり)

doc.rust-lang.org

今回も、Functional Language FeaturesのClosuresについて学びつつ、気になった点をコード確認した結果を記事にしています。

  • versions
$ rustc --version
rustc 1.40.0 (73528e339 2019-12-16)


Closures: Anonymous Functions that Can Capture Their Environment

Closures: Anonymous Functions that Can Capture Their Environment - The Rust Programming Language

github.com

Closure Type Inference and Annotation

下記のClosureでは、パラメータに対する型や戻り値に対する型を利用していません。

let expensive_closure = |num| {
    println!("calculating slowly...");
    thread::sleep(Duration::from_secs(2));
    num
};

下記のように、型をつけることも可能です。

let expensive_closure = |num: u32| -> u32 {
    println!("calculating slowly...");
    thread::sleep(Duration::from_secs(2));
    num
};

しかし、通常はClosure自体は短く、狭いコンテキスト内で使用され、かつ関数内のクローズドな匿名関数であるため、型を推測できます。

そのため、型をつける冗長性を無くすために、一般的に型を記述しません。明示性・明確性を高めたい場合は型をつけてよいと記載されていました。

Fn について

昨日の記事にも出てきた Cacher 内に使用されている Fn についてです。

charaken.hatenablog.com

struct Cacher<T>
    where T: Fn(u32) -> u32
{
    calculation: T,
    value: Option<u32>,
}

クロージャーの型として Fn には3つ利用することが出来ます。

  • FnOnce : Closureが変数の所有権を取得
  • FnMut : 可変な値のOwnerを借用
  • Fn : 不変な値のOwnerを借用

ドキュメントを読んでも分からない・・・

ってことで、まずは定義を確認する。

pub trait Fn<Args> : FnMut<Args> {
    /// Performs the call operation.
    #[unstable(feature = "fn_traits", issue = "29625")]
    extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

pub trait FnMut<Args> : FnOnce<Args> {
    /// Performs the call operation.
    #[unstable(feature = "fn_traits", issue = "29625")]
    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

pub trait FnOnce<Args> {
    /// The returned type after the call operator is used.
    #[stable(feature = "fn_once_output", since = "1.12.0")]
    type Output;

    /// Performs the call operation.
    #[unstable(feature = "fn_traits", issue = "29625")]
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

違いとしては、下記になります。

  • FnOnceself
  • FnMut&mut self
  • Fn&self

上記から推測すると、 FnOnce はClosureをそのまま利用するため1回利用・・・? Fn はアドレス参照なので複数回利用?そして、 FnMut はClosureを変更可能・・・?という風に読み取れますが、ちょっとわからないので、別記事に・・・


まとめ

  • Closureには型定義を一般的には実施しない
    • 明示性・明確性を高めたい場合は必要
  • FnOnceFnMutFn まじでわからん

最後に

Fn 系は今までに触ったことのない(もしくはよしなに頑張ってもらっていた?)概念なので正直分からない・・・

とりあえず、先に進めるために、次はIteratorsについて深めます。