LoginSignup
1
1

More than 3 years have passed since last update.

昨日までJavaJavaしてた人がScalaを触ることになったときのためのメモ

Last updated at Posted at 2020-05-03

Scalaを触ってみて調べた点。
今後も追記予定。
ど初心者なので、指摘等頂けると喜びます。


  • 2020/05/16
    • コメントいただいた点を反映しました。
    • @htsign さん 、@ka2kama さん ありがとうございました。

検証環境

  • Windows10
  • IntelliJ IDEA : 2019.1.2
  • Scala : 2.12.7
  • SBT : 1.3.10

Scalaとは

Scala(スカラ、SKAH-lah[2])はオブジェクト指向言語と関数型言語の特徴を統合したマルチパラダイムのプログラミング言語である。名前の「Scala」は英語の「scalable language」に由来するものである(Wikipediaより)

Scala - Wikipedia

開発環境作成

IntelliJ IDEA を使用する。
以下に導入方法と簡単なチュートリアルがある。

構文

objectとclassの違いは?

  1. object
     ・シングルトンオブジェクトを示す。
     ・シングルトンオブジェクトは自動でインスタンスが生成されるため、明示的にインスタンスを生成することは出来ない。
     ・メソッドに対しては"オブジェクト名.メソッド名"でメソッドにアクセスする。
     ・私は最初Javaのstaticみたいだなと思ったが、objectは唯一のインスタンスであることを示すだけであり、Scalaとしてstaticをサポートはしていないとのこと。

  2. class
     ・シングルトンではないクラスを示す。
     ・シングルトンとは違い自動でインスタンスは生成されないため、明示的にインスタンを生成する必要がある。
     ・メソッドに対しては"インスタンス名.メソッド名"でメソッドにアクセスする。

ざっくり言うとobjectはシングルトンで、classはそうではないということらしい。

参考

インスタンスの作成方法

Javaと同じで普通にnewで作れるが、applyメソッドを定義することでnewがなくてもインスタンスを作成できる。

object Sample extends App {
  val hoge: Hoge = new Hoge
  hoge.hoge()

  //Fuga,Piyoはnewがなくてもインスタンスが作成できる
  val fuga = Fuga()
  fuga.fuga()

  val piyo = Piyo()
  piyo.piyo()
}

//通常
class Hoge {
  def hoge() = println("hogehoge")
}

// case class とすることでapplyが定義されnewが不要となる
case class Fuga() {
  def fuga() = println("fuga")
}

//コンパニオンオブジェクト
class Piyo() {
  def piyo() = println("piyo")
}

object Piyo {
  //applyを定義することでnewが不要となる
  def apply(): Piyo = new Piyo()
}

関数の定義方法

以下が関数定義の構文。
戻り値の型は暗黙的に評価できる場合は省略可能。
関数の内容が1行の場合は{}も不要。

def 関数名(仮引数名1 : , ...) : 戻り値の型 = { ... }

Int型を2つ引数に持つ戻り値がInt型のメソッド。

object Sample extends App {
  println(plus(2, 3))

  def plus(a: Int, b: Int): Int = {
    a + b
  }

  //上記は以下でも同じ
  def plus(a: Int, b: Int) = a + b
}

参考

フィールドの宣言

class 直下に val, var で宣言する。

class Card(val _suit: Suit, val _rank: Int) {
  val suit = _suit
  val rank = _rank
  var value : String
}

コンストラクタでまとめることもできる。
上の例ではvalue以外はコンストラクタとまとめられる。

class Card(val suit: Suit, val rank: Int) {
  var value : String
}

switch文の書き方

Scalaにswitch文はないので、match式で記述する。
_default と同様の動きをする。

<対象式> match {
  case <パターン1> => パターン1結果
  case <パターン2> => パターン2結果
  case _ => デフォルト結果
}
  def toDisplayValue(): String = {

    rank match {
      case 1 => "A"
      case 11 => "J"
      case 12 => "Q"
      case 13 => "K"
      case _ => rank.toString
    }
  }

参考

三項演算子

Scalaに三項演算子はないので、if式を使う。

  val rank: Int = 11

  //Scalaではアクセサがあるので getXXX という書き方はあまりしないそう
  //  def getPoint(): Int = {
  //    if (rank > 10) 10 else rank
  //  }

  def point = if (rank > 10) 10 else rank

参考

アクセサ

Scalaではpublicなフィールドにはアクセサが自動的に定義される。

publicなフィールドはアクセス出来て当然だと思うのだが、厳密にはフィールドはprivateになり、publicアクセサが生成されているそう。
getXXXsetXXXではなくXXXでアクセスするので、アクセサの命名は慣習に従う。

参考

文字列の結合

Javaと同じで+演算子でできるが、文字列補完でもできる。

  //+演算
  override def toString = suit.mark + "の" + toDisplayValue

  //文字列補完
  override def toString = s"${suit.mark}の${toDisplayValue}"

参考

enum

Scalaにはenumがない。

言語で定義されているenumerationは使いづらいらしく、objectを作成して疑似的に作るのが主流のようだ。

sealed abstract class Suit(val mark: String) {
  def getMark() :String = mark
}

object Suit{
  case object SPADE extends Suit("スペード")
  case object HEART extends Suit("ハート")
  case object DIAMOND extends Suit("ダイヤ")
  case object CLUB extends Suit("クラブ")
}

Listの使い方

当記事への @ka2kama さんのコメントがとても詳しいのでリンク。


  • 型の宣言は[]を使う
  var list : List[String]
  • 初期化
var list : List[String] = List("hoge","fuga")
  • 要素の追加は ::
    • イミュータブルなので新しいリストを返す。
  • 注意
    • . は使わない。
    • <要素> :: List で追加する。
    • List :+ <要素> でも追加できるが効率が悪いので使わない方が良い。

  // . での :: の呼び出しはしない
  //  list = list.::("piyo")

  //要素が先
  list = "piyo" :: list

  // :+ でも要素追加できるが効率が悪いため使われないそう
  //  list = list :+ "piyo"

コンストラクタの処理

class直下にそのまま記述する。

参考

ループ

for(要素 <- 配列) でできる。
「要素 <- 配列」をジェネレータという。
ジェネレーターを複数書くことで多重ループを1つのforで記述することが出来る。

  var list: List[Account] = List()
  val names: List[String] = List("hoge", "fuga", "piyo")

  //ループ
  for (name <- names) {
    println(name)
  }

  //2重ループ
  for (name <- names) {
    for (i <- 1 to 3) {
      list = Account(i, name) :: list
    }
  }
  println(list)

  //上と同じ
  //ジェネレーターを複数書くことで多重ループを1つのforで記述することが出来る
  for (name <- names; i <- 1 to 3) list = Account(i, name) :: list
  println(list)

参考

Listのシャッフル

Random.shuffleを使う。

    Random.shuffle(list)

Listの先頭を取得

以下のどちらでもできる。

    list(0)
    list.head
    val c: Card = bill.head

Listから要素を削除

immutableなので削除したい要素をfilterして新たなlistを作成するという手順で疑似的に行う。

下記はどちらも同じ。

    list = list.filter(_ != "hoge")
    list = list.filterNot(_ == "hoge")

継承のパラメータ

自身のコンストラクタと同じ値を渡す。
Javaでいうsuper(name) みたいなことをしたい時には以下のようにする。

class User(name : String) extends AbstractPlayer(name) { ... }

標準入力

readLineを使う。
Scanner#nextLine() と同じ感じで使える。

  val str: String = readLine()

参考

タイトルをインスパイアさせていただきました。

1
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1