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

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

新規登録して質問してみよう
ただいま回答率
85.48%
クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

4回答

1764閲覧

クロージャについて詳しく教えてください

mN6gZkd8fr

総合スコア14

クロージャ

クロージャは、プログラミング言語における関数オブジェクトの一種です。 引数以外の変数を実行時の環境ではなく、 自身が定義された環境において解決することを特徴とします。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

2クリップ

投稿2017/06/21 06:40

編集2017/06/21 06:45

現在、Kotlinの勉強をしていてクロージャを理解しようとしているのですが、考え方があっているのか分かりません。

私の考え方では、クロージャとは、クラスのprivateメンバにアクセスできないのと同様に、本来ならアクセスできないスコープ外の変数を、ラムダ式や無名関数でアクセスできるようにする手段、と理解しています。
この考え方だと、クラスでゲッターやpublicなメソッドを使っているのと何ら変わらない気がしています。

クロージャを使うメリットもあまり理解していないので(オブジェクト指向のカプセル化の概念が邪魔してます…)、分かりやすく説明していただけませんか?
よろしくお願いします。

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

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

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

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

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

guest

回答4

0

私の考え方では、クロージャとは、クラスのprivateメンバにアクセスできないのと同様に、本来ならアクセスできないスコープ外の変数を、ラムダ式や無名関数でアクセスできるようにする手段、と理解しています。

半分合ってますが、半分間違いです。
他スコープの変数であれば、仰る通り他の方法でいくらでもアクセスできます、わざわざクロージャなどを使う必要はありません。

クロージャには色々な使い方があり色々な側面があります、ですので、色々な説明があります
誤解を恐れずにざっくり説明するのであれば、クロージャの特異性は本来破棄されるはずのスコープ外のローカル変数を束縛できるという事です。
ローカル変数の束縛を伴わないクロージャは他の手段で代替可能ですし、かえってわかりにくいコードになりがちです。

なお、こちらの質問で様々な方がクロージャについて説明しています。
ぜひ一読するとよいと思います。

https://teratail.com/questions/41031

投稿2017/06/21 07:15

編集2017/06/21 10:26
pashango2

総合スコア930

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

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

0

kotlin に限らずですが、クロージャはそれを定義したスコープに束縛されます。プロパティアクセス等とは異なるセマンティクスです。例えば javascript で言えば

▼ foo.js

javascript

1function doSomething(f) { 2 f("hello"); 3}

▼ bar.js

javascript

1var a = 1; 2doSomething(function(s) { 3 console.log(a); // a が見える 4 console.log(s); // foo.js から渡された値も扱える 5});

この様に異なるスコープ間でのメッセージパッシングとして使えます。一般的にコールバックという形でクロージャが使われるのはこの理由です。

これを応用すると以下の様に、外からは触れないカウンターを作る事も出来ます。

javascript

1var counter = function() { 2 var count = 0; 3 return function() { 4 count++; 5 return cuont; 6 } 7}(); 8 9console.log(counter()); // 1 10console.log(counter()); // 2 11console.log(counter()); // 3

構造を隠ぺいしつつもスコープ間のデータをやり取りするのがクロージャですので、プロパティとはセマンティクスが異なります。

投稿2017/06/21 07:01

mattn

総合スコア5030

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

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

0

ベストアンサー

まずクロージャの使い方や存在意義についてはこちらが分かりやすいと思います。

クロージャってどんなときに使うの? ~ 利用場面を 3つ 挙げてみる - Qiita

また、javascript等のようにメソッド/メンバ変数に対するアクセス修飾子がない言語だとpublicなgetter、privateなsetterを作るのに重宝したりします。

投稿2017/06/21 06:52

tkturbo

総合スコア5572

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

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

0

クロージャはオブジェクト指向のカプセル化にすぎないんじゃないか…まさしくその通りです

次のコードを見てください。

Kotlin

1fun addNum(a: Int) = { b: Int -> a + b } 2 3fun main(args: Array<String>) { 4 val x = addNum(3) 5 val y = x(5) 6 println(y) 7}

addNumはカリー化されている関数で、クロージャを使っています。引数aaddNumの関数が終了しても、戻り値であるラムダ式で生成され関数でそのまま生き続けるため、x(5)は前に渡した3をたして、8になります。

これをクロージャを使わずに、クラスで書くとこうなります。

Kotlin

1class AddNum constructor(private val a: Int) { 2 operator fun invoke(b: Int) = a + b 3} 4 5fun main(args: Array<String>) { 6 val x = AddNum(3) 7 val y = x(5) 8 println(y) 9} 10

AddNumクラスはaddNum関数と全く同じように使用できます。別にクロージャなんて必要なかったんです。

さらにもう一つ、最初のコードをコンパイルすると"ファイル名$addNum$1.class"という謎のクラスファイルが作られます。このクラスはAddNumとだいたい同じ事(細かいところは異なります)をしているクラスです。そう、クロージャなんてものはクラスでのカプセル化にすぎず、それを自動生成しているだけなのです。

別の視点から見てみましょう。KotlinはJavaVM上で動きます。ですので、JavaVMで実装できないことはKotlinでは実装できません。しかし、JavaVMはクロージャを考慮した作りにはなっていません。Javaにはそもそもクロージャは存在しません(finalまたは実質finalの変数をラムダ式や匿名クラス内で使用できますが、真のクロージャのように環境を取り込んでいるわけではありません)。しかし、一つの自動生成されるクラスとして作成し、クラスのカプセル化を利用して、クロージャで包むべき環境をクラスのフィールドに持たせれば、クロージャと同じ動きができます。なので、Kotlinはクロージャを実装できたのです。もし、クロージャをクラスを使ってその動きを実現できなければ、そもそもクロージャという機能がKotlinに備わることはなかったでしょう(その時点でJavaVM上に実装するという選択肢は無かったと思われますが)。

なんだ、やっぱりクロージャはいらないんだ…。となるでしょうか?二つのコードを見比べて下さい。後者はいかにもオブジェクト指向的な発想ですが、前者のクロージャは関数型でみられる発想です。現代的なプログラミング言語において、関数型プログラミングがしやすいかどうかは、言語選択基準の重要な要素の一つです。クロージャが使えないような言語では、関数型プログラミングがしやすいとはとてもじゃないですが言えません。Javaの代替、強いては打倒Scalaを目指したKotlinにおいて、関数型プログラミングがしやすいことは必須条件であり、クロージャもまた必須の機能であったと思われます。

私が思う結論から言いますと、関数型プログラミングの発想でプログラミングをしない限り、クロージャは役に立つものではありません。旧来のJava的な発想のコードなら、たぶん、使うことは無いでしょう。ですが、関数型プログラミングを取り入れようとした瞬間、クロージャ無しで様々な動作を実現することはかなり厳しいと言えると思います。逆に言えば、関数型プログラミングを知らない限り、クロージャのありがたみはあまりわからないという事です。


私は今日初めてKotlinの書き方を学びましたので、色々間違っているかと思います。おかしな点はご指摘下さい。

投稿2017/06/21 13:44

編集2017/06/21 21:26
raccy

総合スコア21735

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問