学習メモ:Scalaの制御構文 #Scala #dwango
この記事について
DOING
Scalaの制御構文
言葉の定義
ScalaはCやJavaなどの手続き型の言語に比べて、文よりも式になる構文が多いため、変数などの状態をできるだけ排除したわかりやすいコードが書きやすい。
構文 (Syntax)
- そのプログラミング言語内でプログラムが構造を持つためのルール
- プログラミング言語内で特別扱いされるキーワード(class, val, ifなど)
- 正しいプログラムを国姓するためのルール(クラスの中身は{}で括られる)
式 (Expression)
- プログラムを構成する部分のうち、評価することで値になるもの
1
や1+2
は数値になり、"hoge"
は文字列の値になる
文 (Statement)
- プログラムを構成する部分のうち、評価しても値にならないもの(⇔式(Expression))
val i = 1
は、定義全体としては値を持たない。(変数iは定義され,iの値は1になるけれど)
{}式
- {}構文の一般形は
{exp1; exp2; ... expN; }
- ;は改行で区切られていれば省略できる。
- exp1からexpNを順番に評価し、expNを評価した値を返す。
Scalaにおける一般的なメソッド定義
scala > def foo(): String = { "foo" + "foo" }
if式
Javaとほぼ同じだったのでスキップ
練習問題
var age: Int = 5という年齢を定義する変数とvar isSchoolStarted: Boolean = falseという就学を開始しているかどうかという変数を利用して、 1歳から6歳までの就学以前の子どもの場合に“幼児です”と出力し、それ以外の場合は“幼児ではありません”と出力するコードを書いてみましょう。
自分の回答
var age: Int = 5 var isSchoolStarted: Boolean = false if(1 <= age && 6 <= age && !isSchoolStarted){println("幼児です")}else{println("未熟児です")}
while式
Javaとほぼ同じだったのでスキップ
練習問題
do whileを利用して、0から数え上げて9まで出力して10になったらループを終了するメソッドloopFrom0To9を書いてみましょう。loopFrom0To9は次のような形になります。???の部分を埋めてください。
def loopFrom0To9(): Unit = { var i = ??? do { ??? } while(???) }
自分の回答
i++みたいなのってScala使えないんですね・・・
def loopFrom0To9(): Unit = { var i = 0 do { println(i) i += 1 } while(i < 10) }
for式
Javaの制御構文と似た使い方ができるものの、全く異なる構文です。for式の本当の力を理解するには、flatMap, map, withFilter, foreachといったメソッドについて知る必要がありますが、ここでは基本的なfor式の使い方のみを説明します。
とあるので、心してかかりたいと思います。
基本的な構文
for(ジェネレータ1; ジェネレータ2; ... ジェネレータn) A # ジェネレータ1 = a1 <- exp1; ジェネレータ2 = a2 <- exp2; ... ジェネレータn = an <- expn
- ジェネレータって言ってるのが条件っぽい(a1 <- exp1など)
- exp1〜expnには、ある数の範囲を表す式を使える
1 to 10
→1から10まで (10を含む)1 until 10
→1から10まで (10を含まない)
scala> for(x <- 1 to 5; y <- 1 until 5){ println("x = " + x + " y = " + y) } x = 1 y = 1 x = 1 y = 2 x = 1 y = 3 x = 1 y = 4 x = 2 y = 1 x = 2 y = 2 x = 2 y = 3 x = 2 y = 4 x = 3 y = 1 x = 3 y = 2 x = 3 y = 3 x = 3 y = 4 x = 4 y = 1 x = 4 y = 2 x = 4 y = 3 x = 4 y = 4 x = 5 y = 1 x = 5 y = 2 x = 5 y = 3 x = 5 y = 4
ループ変数の中から条件にあったものだけを絞りこめる
以下の例だと x!=y
が追加されたことによってx, y同じ値のものが表示されなくなっています。
scala> for(x <- 1 to 5; y <- 1 until 5 if x != y){ println("x = " + x + " y = " + y) } x = 1 y = 2 x = 1 y = 3 x = 1 y = 4 x = 2 y = 1 x = 2 y = 3 x = 2 y = 4 x = 3 y = 1 x = 3 y = 2 x = 3 y = 4 x = 4 y = 1 x = 4 y = 2 x = 4 y = 3 x = 5 y = 1 x = 5 y = 2 x = 5 y = 3 x = 5 y = 4
コレクションの要素を1つ1つ辿って処理を行うために使うことも可能
例えばListの中身の文字列をすべて出力する処理
scala> for(e <- List("A", "B", "C", "D", "E")) println(e) A B C D E
コレクションの要素を辿って、加工して新しいコレクションを作成できる
この場合ジェネレータで指定したリストの要素の前にPreが付いた要素を持つリストが新しく作成されています。
scala> for(e <- List("A", "B", "C", "D", "E")) yield { | "Pre" + e | } res9: List[String] = List(PreA, PreB, PreC, PreD, PreE)
yieldキーワードを使ったfor式はfor式ではない
- for-comprehensionと呼ぶ事がある
- yieldキーワードを使うことで、コレクションの要素を加工して返すという異なる用途に使える
練習問題
1から1000までの3つの整数a, b, cについて、三辺からなる三角形が直角三角形になるような a, b, cの組み合わせを全て出力してください。直角三角形の条件にはピタゴラスの定理を利用してください。 ピタゴラスの定理とは三平方の定理とも呼ばれ、a ^ 2 == b ^ 2 + c ^ 2を満たす、a, b, c の長さの三辺を持つ三角形は、直角三角形になるというものです。
自分の回答
^
が使えなくて微妙にハマった・・・
for (a <- 1 to 1000; b <- 1 to 1000; c <- 1 to 1000) if (a * a == b * b + c * c) { println("a=" + a + ", b=" + b + ", c=" + c) }
模範解答と違ったところ
for文の中にif文を入れ込むかfor文とif文を分けるか。
模範解答はfor (a <- 1 to 1000; b <- 1 to 1000; c <- 1 to 1000 if a * a == b * b + c * c)
で
自分の回答はfor (a <- 1 to 1000; b <- 1 to 1000; c <- 1 to 1000) if (a * a == b * b + c * c)
match式
match式は使い方によって非常に幅のある制御構造です
基本構文
- Javaのswitch-caseみたいなやつ
- Scalaはbreakしなくていい(フォールスルー動作がない)
_
はdefaultのようなもの(ワイルドカードパターン)- match式を使う際は漏れがないように、ワイルドカードパターンを利用することが多い。
マッチ対象の式 match { case パターン1 [if ガード1] => 式1 case パターン2 [if ガード2] => 式2 case パターン3 [if ガード3] => 式3 case ... case パターンN => 式N case _ => "nothing" }
パターンをまとめる
Javaのswitch-caseのときはフォールスルーさせていたけど、Scalaの場合はOR(|)でつなげられる。
"abc" match { case "abc" | "def" => println("first") println("second") }
パターンマッチによる値の取り出し
switch-case以外の使い方として、コレクションの要素の一部にマッチさせる使い方もある。
下の場合、「リストの先頭要素が"A"で5要素」のパターンにマッチすると残りが表示され、しなければ"nothing"が表示される。
scala> val lst = List("A", "B", "C", "D", "E") lst: List[String] = List(A, B, C, D, E) scala> lst match { | case List("A", b, c, d, e) => | println("b = " + b) | println("c = " + c) | println("d = " + d) | println("e = " + e) | case _ => | println("nothing") | } b = B c = C d = D e = E
+ガード式なパターンマッチもできる
さっきのプログラムにガード式(今回の場合if b != "B"
)を追加すると"nothing"が表示されるようになる。
scala> val lst = List("A", "B", "C", "D", "E") lst: List[String] = List(A, B, C, D, E) scala> lst match { | case List("A", b, c, d, e) if b != "B" => | println("b = " + b) | println("c = " + c) | println("d = " + d) | println("e = " + e) | case _ => | println("nothing") | } nothing
パターンマッチのパターンのネストが可能
- Listを要素として持つListをパターンマッチすることもできる
- パターンの前に
@
がついているのはasパターンと呼ぶ@
の後に続くパターンにマッチする式を@
の前の変数(今回の場合a)に束縛する。
- このプログラムの場合パラメータがListで先頭要素がList("A")で2要素もつ場合matchし、List(A)ともう一つの要素が表示されている
scala> val lst = List(List("A"), List("B", "C", "D", "E")) lst: List[List[String]] = List(List(A), List(B, C, D, E)) scala> lst match { | case List(a@List("A"), x) => | println(a) | println(x) | case _ => println("nothing") | } List(A) List(B, C, D, E)
パターンマッチの場合、値をとりだすことはできない
scala> (List("a"): Any) match { | case List(a) | Some(a) => | println(a) | } <console>:14: error: illegal variable in pattern alternative case List(a) | Some(a) => ^ <console>:14: error: illegal variable in pattern alternative case List(a) | Some(a) => ^
値を取り出さないパターンマッチは可能。ただこれいつ使うんだろう。型を見たい時とかだろうか・・・
(List("a"): Any) match { case List(_) | Some(_) => println("ok") }
型によるパターンマッチ
- Scalaではcaseに値ではなく型を指定することも可能
- 特定の型に所属する場合にのみマッチするパターンは
名前:マッチする型
と書く - AnyRef=JavaでいうObject型(なんでも格納できる)
- 例外処理やequalsの定義などで使うことがある
- しばしばキャストの代わりにパターンマッチが用いられるので覚えておくこと
このプログラムの場合AnyRefがStringにマッチしているので、すべてを大文字にした結果が表示されています。
scala> import java.util.Locale import java.util.Locale scala> val obj: AnyRef = "String Literal" obj: AnyRef = String Literal scala> obj match { | case v:java.lang.Integer => | println("Integer!") | case v:String => | println(v.toUpperCase(Locale.ENGLISH)) | } STRING LITERAL
JVMの制約による型のパターンマッチの落とし穴
- 型変数を使った場合、正しくパターンマッチが行われない。
- このプログラムだとcaseにList[Int]とList[String]を書いているが、パターンマッチでは区別できない
scala> val obj: Any = List("a") obj: Any = List(a) scala> obj match { | case v: List[Int] => println("List[Int]") | case v: List[String] => println("List[String]") | } <console>:16: warning: non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure case v: List[Int] => println("List[Int]") ^ <console>:17: warning: non-variable type argument String in type pattern List[String] (the underlying of List[String]) is unchecked since it is eliminated by erasure case v: List[String] => println("List[String]") ^ <console>:17: warning: unreachable code case v: List[String] => println("List[String]") ^ List[Int]
型変数を含む方のパターンマッチはワイルドカードパターンを使うと良い
obj match { case v: List[_] => println("List[_]") }
練習問題
new scala.util.Random(new java.security.SecureRandom()).alphanumeric.take(5).toList
以上のコードを利用して、 最初と最後の文字が同じ英数字であるランダムな5文字の文字列を1000回出力してください。 new scala.util.Random(new java.security.SecureRandom()).alphanumeric.take(5).toListという値は、呼びだす度にランダムな5個の文字(Char型)のリストを与えます。なお、以上のコードで生成されたリストの一部分を利用するだけでよく、最初と最後の文字が同じ英数字であるリストになるまで試行を続ける必要はありません。これは、List(a, b, d, e, f)が得られた場合に、List(a, b, d, e, a)のようにしても良いということです。
自分の回答
うまくいかずギブアップ・・・
var i = 0 while(i <= 1000){ val lst: List[Char] = new scala.util.Random(new java.security.SecureRandom()).alphanumeric.take(5).toList lst match { case List(a, b, c, d, e) if a == e => i += 1 println(lst) } }
模範解答
問題文の
なお、以上のコードで生成されたリストの一部分を利用するだけでよく、最初と最後の文字が同じ英数字であるリストになるまで試行を続ける必要はありません。これは、List(a, b, d, e, f)が得られた場合に、List(a, b, d, e, a)のようにしても良いということです。
これを実装すると実にすっきりします。あとforかwhileどっちで回すといいとかあるのかな。
for(i <- 1 to 1000) { val s = new scala.util.Random(new java.security.SecureRandom()).alphanumeric.take(5).toList match { case List(a,b,c,d,_) => List(a,b,c,d,a).mkString } println(s) }
この章での疑問点
if文の順序
age => 1 && age <=6 && !isSchoolStarted
だとNGで
1 <= age && 6 <= age && !isSchoolStarted
だとコンパイルが通るのはなぜだろうか・・・
値を取り出さないパターンマッチの使い所
- 値を取り出さないパターンマッチは可能なのはわかったけど、これいつ使うんだろう。
進捗
DONE
TODO
- クラス
- オブジェクト
- トレイト
- 型パラメータと変位指定
- 関数
- Scalaのコレクションライブラリ
- ケースクラスとパターンマッチング
- エラー処理
- Implicit
- 型クラスの紹介
- FutureとPromise
- テスト
- Javaとの相互運用
- S99の案内
- トレイトの応用編:依存性の注入によるリファクタリング
次回はクラスをやります。次回はいつだろう・・・年内にドワンゴテキスト終わらせたい。
ドワンゴScala研修テキスト学習中 #dwango #scala
私がdodosoftで得られたもの #dodosoft
この記事はdodosoft Advent Calendar 2016 2日目です。
昨日はddddbirdでした!
この記事について
私がdodosoftに参加して得られたものをまとめて、dodosoftメンバーに感謝の意を伝えたいための記事です。
dodosoftで得られたもの
- 旦那
- 勉強する習慣
- ソフトウェア工学の基礎
旦那
旦那とはdodosoftで出会いました。
出会いが勉強会なので、土日に勉強したり、勉強会に参加することに理解があります。
最近だともくもくデートしよう!って12時から21時くらいまでYahoo!のLODGEにこもって個室で勉強したり、エンジニアとしてのびのび活動するために支えてくれる最高のパートナーをdodosoftで見つけられました。
みんなありがとう!
勉強する習慣
これは一番大きいかなと思います。
学生時代まで専門的な勉強なんてテスト前と卒業研究くらいでしかやっていなかった自分にとって、同期は色々知っててすごいなと思って勉強しなきゃと焦ってたんですよね。今も焦ってますが。笑
そんなときに、入社して2,3ヶ月くらいかな?、定期的にすごい同期と時間かけて基礎的な部分を議論しながら勉強していると聞いて参加したいってなって。
ここに参加していなかったら技術もっとやりたいとは思ってなかっただろうし、本棚が技術書であふれることもなかっただろうし、仕事がこなせればいやーくらいにしかやってなかったと思います。
ソフトウェア工学の基礎
自分は高専卒で周りはほとんど大学院修士卒だったので、圧倒的に学んできた量が違って、それに負い目を感じていました。
しかも、ソフトウェア工学の基礎の部分ってなかなか社外イベントでもやらない。結構流行りのフレームワークとかが多い。
でも、新しいものを理解するためにやっぱり基礎って大事だなってすごい思うので、ソフトウェア工学の基礎を取り上げて時間かけて輪読することができて本当によかった。
これからもよろしく!
こんなにたくさんのものが得られるdodosoftなのでこれからも続けていきますー!
次回予告
明日の担当はYSKNです!前職同期だと最年少(私)から最年長(YSKN)へのバトン!w
クリスマスパーティーの準備なう
Advent Calendar毎日更新してて、今日は久々に担当日じゃなかったという。
せっかくだから隙間もブログ書こうかなっていう。
楽しみで仕方がない
子供の頃から家でのクリスマスパーティーに憧れてたのでやっと実現できる!
子供のころはそういう風習もなかったし、こっちきてからも都心に住んだこともなかったから呼びづらかったし、そもそも人を誘うのが苦手なので、今までホームクリスマスパーティーにすごく憧れてました!
今準備しているもの
もう家にあるもの
前日用意するもの
- クリスマスケーキ
- チキン(丸焼き)
- ウィルキンソン(割りもの)
- お茶
- 生ハム
- ピザ
同僚ありがとう
自分のノリにノッてくれた同僚各位ありがとう。
今年の登壇振り返り:東京高専卒業生が後輩に送る楽しい授業 先輩の人生に学び、今日からできることを見つけよう #東京高専で授業やってる #高専
この記事は松村Advent Calendar 2016 13日目です。
今年は社外で13回登壇(うちスライドありは11回)したのですが、 まったく振り返りできてないので振り返ろうかと思います。
イベント概要
東京高専情報工学科の2年生〜5年生に卒業生の声で社会のことや働き方について伝える授業でした。 メイン講師以外が完全に「Twitterの合間に授業やってる」感じになってとても新鮮でしたw
Togetter
他のパネラーの方のブログ
一緒に登壇した柴山 嶺(@serima)さんがブログ書いていたのでこちらも見てみてください。 serima.co
発表資料
メイン講師のりゅーかん(@RyuhiKanno)、こと菅野くんの発表資料を貼っておきます!
161109_東京高専授業_v1.3.pdf - Google ドライブ
登壇のきっかけ
前から今高専の人に自分が卒業してから感じたこと、体験したことを伝えたいと思っていたので、菅野くんが以前東京高専に授業行ったってFacebookの投稿に「私も次あるならやりたい!」って話したのがきっかけです。その後本当に次回があったので、その時に声かけてもらいました。
本当は自分の高専から呼ばれたいですが、OB向けの会誌の執筆くらいしか来ないですねw
母校から声かけられるくらい頑張りたいです。
登壇ふりかえり
↑で紹介した柴山さんも書いていたけれど、2年生向けのキャリアの話って難しいなと思いました。
最初予定していた内容より本当にざっくばらんに、高専時代の思い出話とか、どんな学生だった?って話とかそういう、もっともっと身近な話が中心になりました。
あとTogetter見れば分かるけれどTwitterがかなり盛り上がったなと思っています。
やっぱり高専生ピュアでシャイなのでTwitterできた質問について適宜パネルセッションで取り上げたり、リプしたりと、とても柔軟な授業でした。こういう授業の形を取るのはお試しだったのだけれど面白かった!
TwitterというSNSに流すことで他の高専の人や、パネラーのフォロワーからも注目されていましたね。
次回予告
次回は!!やっと!!私じゃない人!!!
Rubyistな主人、もといmuramurasanで「自作gem:connect_gsi_api」についてです。楽しみー!
今年の登壇振り返り:Geek Women Japan 2016 #gwjp2016 #geekwomenjapan
この記事は松村Advent Calendar 2016 12日目です。
今年は社外で13回登壇(うちスライドありは11回)したのですが、 まったく振り返りできてないので振り返ろうかと思います。
イベント概要
Geek Women Japan 2016はエンジニア女子が中心となって一同に集まり、ギークなセッションを繰り広げるカンファレンスです。
私と強力な友人が主催です。今回が第一回です。
geekwomenjapan.github.io
Togetter
発表資料
「デザイン思考はいいぞ」というタイトルでLTを発表しました。 speakerdeck.com
登壇のきっかけ
Geek Women Japan 2016で私が運営メンバーとして参画しているdots.女子部が共催コミュニティとして、Ladies that UX Tokyoさんとコラボセッションを行ったので、その際にメンバーからお願いがあったので登壇しました。
本当は運営で手一杯だったのでLTなんかできるかな、と思いましたがなんとかなりました。
あとコラボセッション相手がUXに特化したコミュニティだったので、できれば特定技術に限らないけど専門性もあるセッションをしたいなと思い、デザイン思考について発表しました。
なぜデザイン思考にしたかというと、現在東工大のCBEC(チーム指向越境型アントレプレナー育成プログラム)のEDP(エンジニアリング・デザイン・プロジェクト)に参加しているのでちょうど学んだことや良さを発信したかったテーマの一つだったからです。
登壇ふりかえり
他のdots.女子部メンバーが技術やキャリアの話をしていたので、個性出せたかなと思っています。
デザイン思考の良さを伝えきれたかは自信がないけれど「デザイン思考というサービス開発の方法がある」ということを知ってもらえただけでも満足でした。
またTwitterを見ると「名前しか聞いたことなかったからちょっと勉強してみよう!」とか「長期でやれるのいいなー」などデザイン思考に興味を持ってもらえてよかったです。
仕事やってると思うのですが、それぞれの専門性が共通言語をもって最大限に発揮できるなら素晴らしいと思っていて、デザイン思考はそれをするための手段として取り入れたい手法の一つなので今後も知名度向上の一助になれたら、仕事やりやすくなるかなって思いました。
次回予告
明日は「東京高専卒業生が後輩に送る楽しい授業 先輩の人生に学び、今日からできることを見つけよう」について私が書きます。
今年の登壇振り返り:DevFest Tokyo 2016 #devfest16
この記事は松村Advent Calendar 2016 11日目です。
今年は社外で13回登壇(うちスライドありは11回)したのですが、 まったく振り返りできてないので振り返ろうかと思います。
イベント概要
DevFest は、Google Developer Group (GDG) コミュニティによって世界各地で開かれるデベロッパー向けイベントです。
gdg-tokyo.connpass.com
Togetter
他のセッションも混じってますが、15, 16ページ目が私のセッション関連です。
togetter.com
FRESH!! by Abema TV
発表の様子がAbema TVの「FRESH!!」で実況・録画されました。2:59:00〜3:13:10が私のセッションです。 abemafresh.tv
発表資料
「女性エンジニアコミュニティの力」というタイトルで発表しました。 speakerdeck.com
登壇のきっかけ
DevFest Tokyo 2016の共催コミュニティGTUG Girlsのyanzmさんが募集をかけていたので、立候補してみました。
ちょうど11/3のGeek Women Japan 2016の準備をかなりしていた頃だったので女性エンジニアコミュニティについてもっともっと知ってもらいたくて、たくさんの方が来るDevFestで話そうと思いました。
JJUG CCC以来の大規模イベントでのセッションでしたが、一度JJUG CCCでやれたから今回もやれる!と思って登壇しました。
登壇ふりかえり
会場が埋まるほどの盛況ではなかったですが、聴衆が男女半々くらいで聞いてもらえてよかったなと思いました。
また、直前に二人がセッションしたのですが、その空気がゆるめだったので空気感をあわせるのが途中からできませんでした。
誰かと同じ枠でセッションするときは空気感をある程度あわせないといけないと思いました。
あとはGeekWomenJapan Advent Calendar 2016の1日目でも書きましたが、自分がかなり伝えたかった「女性エンジニア」から「女性」というprefixを取りたいという話についても悪くない反応があったのがよかったです。
次回予告
明日は「Geek Women Japan 2016」のコラボセッション枠で話したことについて私が書きます。