Scala について学習してみる

f:id:ts0818:20190812152247j:plain

rollingstonejapan.com

北極海北大西洋の間にある世界最大の島グリーンランド。過去1000年の間にわずか数回しか発生していないというレベルの大規模融解が、今年加速している。8月初旬には、地表近くで史上最高気温を計測。「全て溶けて流れ出さないように祈るのみだった」と、気功科学者は語る。

北極圏グリーンランドで史上最高気温を計測、氷床の融解が急加速 | Rolling Stone Japan(ローリングストーン ジャパン)

むちゃくちゃ暑いしね...地球温暖化ってやつ?

でも、なんか、

business.nikkei.com

⇧  氷河期に突入って話もあって...どうすれば?

あ、どうもボクです。地球がどうなるか分からないというのに、今日もプログラミングを学習するのであった、というわけで、Scala です。

Scala については、

rirakkumya.hatenablog.com

⇧  上記サイト様の記事が面白いです。

日本の Scala 界隈では、Scala忍者こと、吉田 憲治 (@xuwei_k)さんが、Scalaトップランナー的存在のようです。

xuwei-k.hatenablog.com

GitHub にもいろいろ情報を上げてくれていらっしゃいます。

github.com

そんなわけで、Scala 環境を、前々回で作ったので、 Scala について学習していきますか~。

それでは、レッツトライ~。 

 

Scala におけるデータ型

 公式のサイトによりますと、

docs.scala-lang.org 

AnyVal は値型に相当します。 事前に定義された9つの値型が存在し、それらDoubleFloatLongIntShortByteCharUnitBooleanは null非許容です。

統合された型 | Scala Documentation

AnyRef は参照型を意味します。全ての値型でない型は参照型として定義されます。Scalaでは全てのユーザー定義型はAnyRefのサブタイプになります。 もしScalaJava実行環境上で利用されるなら、AnyRef は java.lang.Object に相当します。

統合された型 | Scala Documentation

⇧ っていう説明にある通り、大きく分けて、

  • 値型
  • 参照型

で分かれるという点では、Javaと似てるけど、微妙に異なる点もあると。

Any は全ての型のスーパータイプであり、トップ型とも呼ばれます。 Anyは equalshashCode、そして toStringのようないくつかの普遍的なメソッドを定義しています。 そしてAnyValAnyRef という2つの直系のサブクラスを持ちます。

統合された型 | Scala Documentation

⇧  そう、この、Scala の Any っていう 概念は、Java には無さそうなんですよね。上記のような普遍的なメソッドは、Javaだと、java.lang.Object が担っていたような...。

 

それと、Javaだと、値型(プリミティブ型)のラッパークラスってあると思うんだけど(例えば、int のラッパークラスは、Integer みたいな)、Scala のAnyVal ではそのへんが無い感じですかね。

 

ScalaJava の関係

Java 8 で入ってきた要素って、ほとんど、Scala にインスパイアされたものらしい。

postd.cc

⇧  上記サイト様が詳しいです。

なので、Java 8 から導入された関数型インターフェイス とかも、Scala でやってるような関数型プログラミングを実現したいってことが目的だったのではないかと。

そして、Scala は、「;セミコロン)」が不要のようです。

また、Scala は、NullPointerException がほとんど起こらないような実装をしていくようでして、Nullチェックの悪夢から解放されるのだと。

ビバ!レボリューション!

 

何はともあれ、Scala の文法を練習(変数)

まぁ、練習していきますか。

Scala の特徴というか、関数型のプログラミングに共通なのかは分かりませんが、変数は基本的にimmutable(不変。再代入不可)で使用するという考えらしい。

変数なのに、変わらない?それって、定数ですやん?っていうツッコミは無しで。 

一応、変数の定義には、

  • val
    immutable:再代入不可
  • var
    mutable:再代入可

の2つが使えるようです。 なんか、VB6とかも、変数って、val、var とかだった気が...意味合いは違うと思いますけど。

で、String型で immutable な変数を定義する場合は、

val msg: String = "Hello World"    

みたいに書けると。

さらに、Scalaには「型推論」があるので(Javaでも、Java 9 からvarが導入されたので、型推論できるかと)、データ型を省略して、

val msg = "Hello World"    

って書いてもOKらしい。

val は、再代入不可なんで、変数の中身を変えようとすると、

f:id:ts0818:20190812161249p:plain

⇧  怒られます。再代入したい場合は、var で宣言するしかないかと。もしくは、まったく違う変数名で、新しく「val msg2」みたいな変数を作ればOKらしい。

 

何はともあれ、Scala の文法を練習(データ型)

データ型もいろいろあるので、書き方を試してみる。 

    // ■整数
    // Int型
    val i: Int = 100
    // val i = 100 //← 型推論
    // Long型
    val l: Long = 8888888888L
    // val l = 8888888888L //← 型推論
    // ■浮動小数点数
    // Double型
    val d: Double = 1234567.8
    // val d = 1234567.8 //← 型推論
    // Float型
    val f: Float = 1234.56F
    // val f = 1234.56 //← 型推論

    // ■文字
    // Char型
    val c: Char = 'a'
    // val c = 'a' //← 型推論
    // ■文字列
    // String型
    val s: String = "Oh my gosh!"
    // val s = "Oh my gosh!" //← 型推論
    // ■論理値
    var flug: Boolean = true
    // val flug = true //← 型推論

Long型の値の末尾にL、Float型の値の末尾にFを付けるのは、Java と同じ感じですかね。

出力がちょっと独特?

 
object HelloWorld {
  def main(args:Array[String]): Unit ={

    val msg: String = "Hello World"
    // val msg = "Hello World"

    // ■整数
    // Int型
    val i: Int = 100
    // val i = 100 //← 型推論
    // Long型
    val l: Long = 8888888888L
    // val l = 8888888888L //← 型推論
    // ■浮動小数点数
    // Double型
    val d: Double = 1234567.8
    // val d = 1234567.8 //← 型推論
    // Float型
    val f: Float = 1234.56F
    // val f = 1234.56 //← 型推論

    // ■文字
    // Char型
    val c: Char = 'a'
    // val c = 'a' //← 型推論
    // ■文字列
    // String型
    val s: String = "Oh my gosh!"
    // val s = "Oh my gosh!" //← 型推論
    // ■論理値
    var flug: Boolean = true
    // val flug = true //← 型推論
    println(s"s: $s, i: $i, d: $d, f: $f")

    // println("Hello World");
  }
}
// 出力結果→ s: Oh my gosh!, i: 100, d: 1234567.8, f: 1234.56

f:id:ts0818:20190812170416p:plain

みたいな感じ。

フォーマット決めたり、計算とかもできるらしい。

println(f"s: $s%10s, i: ${i + 10}%-10d, d: $d%10.3f, f: $f%10.2f")

f:id:ts0818:20190812171204p:plain

 

何はともあれ、Scala の文法を練習(制御構文)

JavaScala でだいぶ異なるのが、制御構文の扱いではないかと。Scalaでは、式 というもののが存在するので、制御構文をそのまま変数に代入できるらしい。 

■ if文、if式

どういうことかというと、 Javaのif文だと、

int score = 99;
String result = null;
if (score > 99) {
  result = "Oh my gosh!"
} else if (score > 60) {
  result = "Pretty awesome"
} else {
  result = "so fly!!"
}
System.out.println(result);

Scalaのif式だと、

val score: Int = 99;
val result: String = 
  if (score > 99) "Oh my gosh!"
  else if (score > 60) "Pretty awesome"
  else "so fly!!"
System.out.println(result);    

みたいに、変数に直に代入できると。

 

■switch文、match式 

Java の switch文に該当するのが、Scala では、match式というものらしい。

Javaのswitch 文 だと、

String brand = "JPN";
BigDecimal tradeLimit = BigDecimal.valueOf(1000.0);
Map<String, BigDecimal> currencyMap = new HashMap<>();
currencyMap.put("BTC", BigDecimal.valueOf(1097604.0));
currencyMap.put("ETH", BigDecimal.valueOf(20627.0));

if (Objects.isNull(brand)) {
  
} else switch (brand) {
  case "BTC":
    if (tradeLimit.compareTo(Objects.nonNull(currencyMap.get("BTC")) ? currencyMap.get("BTC") : tradeLimit.add(BigDecimal.ONE)) >= 1) 
      System.out.println("買いで");
    break;
  case "ETH":
    if (tradeLimit.compareTo(Objects.nonNull(currencyMap.get("ETH")) ? currencyMap.get("ETH") : tradeLimit.add(BigDecimal.ONE)) >= 1) 
      System.out.println("買いで");
    break;
  case "QTUM":
  case "XLM":
    System.out.println("様子見");
    break;
  default :
    break;
}

みたいな感じになりますが、Scalaのmatch式では、

val brand: String = "JPN"
val limit: BigDecimal = BigDecimal(1000.0)
val map: Map[String, BigDecimal] = Map(
  "BTC" -> BigDecimal(1097604.0),
  "ETH" -> BigDecimal(20627.0)
)
var result: String = brand match {
  case "BTC" if (limit.compareTo(map.getOrElse("BTC", (limit + BigDecimal(1)))) >= 1) => "買いで"
  case "ETH" if (limit.compareTo(map.getOrElse("ETH", (limit + BigDecimal(1)))) >= 1) => "買いで"
  case "QTUM" | "XLM" => "様子見"
  case other => s"どれにも当てはまらん...: ${other}"
}
println(result)

みたいな感じになるようです。

2019年8月26(月):追記  ↓  ここから

Javaでも、switch式が導入されてるらしい。

nowokay.hatenablog.com

nowokay.hatenablog.com

Java12でプレビューとしてswitch式が入って、Java13で正式化できるよう作業が進んでいます。 そんな中、switch式を正式化するJEPのドラフトが出ていました。

JEP draft: Switch Expressions 

追記 あっというまにドラフトではなくなっています JEP 354: Switch Expressions

switch式の値付きbreakはbreak-withになることがほぼ確定(追記ありyieldになりました) - きしだのHatena

⇧  きしださんのブログ情報によると、Java 13 で正式に導入されたようです。

2019年8月26(月):追記  ↑  ここまで

 

■while文、do while文

JavaScala、ともに変わらないようなので、割愛。

 

■for文、for式

for については、だいぶ、様子が変わってきます。

Javaだと、

for (int i = 0; i <= 10; i++) {
  if (i == 10) {
    System.out.println("10カウント");
  }
}    

みたいな感じですが、

 

for (i <- 0 to 10) {
  if (i == 10) {
    println("10カウント")
  }
}

てな具合。yield っていう概念も出てくるようです。

var results = for (i <- 0 to 10; j <- 0 to 10 if i != j) yield s"$i, $j"
for (el <- results) println(el)

ってな具合。

yield の ある・なしって何が違うの?ってなことについては、

qiita.com

⇧  上記サイト様が詳しいです。

 

とりあえず、基本的なことがらについて、Scalaの学習をしてみました。Scala 特有の概念がまだ全然まとめれていないので、時間あるときにまとめていきたいですね。

少しづつ、Scalaに慣れていきたいですね。

今回はこのへんで。