Scala/関数/関数リテラル

Scala/関数/関数リテラル

関数リテラルというか、無名関数を作るということ。

基本

見た目が記号ランランで非常に読みにくいが・・・イコールを挟んで左が入れるための変数宣言で、右が関数本体となる。

val myadd:(Int, Int) => Int = (a:Int, b:Int) => {
  a + b
}:Int

ここが関数を入れる変数宣言。変数名に続き引数の型と戻りの型を型名だで指定している

val myadd:(Int, Int) => Int

ここが関数本体。仮引数に続き処理、最後に戻りの型を指定している。

(a:Int, b:Int) => {
  a + b
}:Int

戻りの型は最後まで読めば Scala では自明になるので書かれることはほぼ無い、かなり高い確率で省略される。

関数リテラルと def で宣言した関数は何が違うか?

使えるタイミングが違う

関数の宣言と代入は JavaScript のこのような関係に似ている。

function hoge(a, b){
    return a + b;
}
var hoge = function(a, b){
    return a + b
};

変数のへの代入であって、宣言ではないので、このようなことができない。

println(myadd(1, 2)) // これはできない
val myadd:(Int, Int) => Int = (a:Int, b:Int) => {
  a + b
}
println(myadd(1, 2))

呼び出し方法が違う

def で宣言した関数は引数なしの場合関数名のみで括弧無しで呼び出せるが、 関数リテラルは括弧なしの場合は関数オブジェクトの操作として扱われるので呼び出しには必ず括弧が必要になる。

変形記法

Scala は関数の記述に関して変形記法がものスゴイたくさんあって、混乱するのでまとめる

引数無し、1ステップ

関数宣言同様に1ステップの処理ならば中括弧省略が可能になる

var a = () => "hoge"

全体括弧付き

通所の関数リテラルだけど全体を中括弧で囲った版。これは基本的は括弧なし版と同じ。

var a = { () => "hoge" }

特に何も無いがブロック感を強調したい時に使うといいだろう

型推論を伴う引数に関数リテラルを使う場合1

関数を引数にとる関数のパラメータとしてリテラル表記使う場合。 その関数のシグネチャから引数に取る関数の構造が確定できる部分があるので通常の関数リテラルよりもさらに省略して書くことが可能になる

必要とする関数リテラルの引数が1個の場合その引数指定部分の括弧を省略して書ける

def hoge(f:(Int) => Int):Int = {
  f(1)
}
println(hoge(x => x + 1))  // => 2
println(hoge(x => x + 2))  // => 3

型推論を伴う引数に関数リテラルを使う場合2

必要とする関数リテラルの引数が1個の場合でその関数リテラル中でたった1回しか使われない場合、引数名すら省略して書ける。

この場合アンダースコアが唯一の変数として関数内部で機能する

def hoge(f:(Int) => Int):Int = {
  f(1)
}
println(hoge(_ + 1))  // => 2
println(hoge(_ + 2))  // => 3

アンスコを使うことでその周辺が関数であることとなるのだろう。これは若干過激過ぎると思うので

println(hoge({ _ + 1 }))  // => 2

このぐらいが優しいと思う

無名関数の即時実行

特にこういう用途があるかどうか知らんが JavaScript でやっていたのでできるかなと

(funciton(_hoge){ console.log(_hoge);})("hogehoge");

こういうやつである。

println(((a:Int, b:Int) => {
  a + b
}:Int)(1, 2))

できた!サスガ

scala/basic/function/literal.txt · 最終更新: 2020-08-03 13:16 by ore