- src/main/scala/Main.scala
object Main {
def main(args: Array[String]): Unit = {
println("hello scala!")
}
}
- build.sbt
name := "NiigataScala"
version := "0.1"
scalaVersion := "2.10.2"
- ソースは普通は src/main/scala 以下に置く
- Javaと一緒に使う場合、java ファイルは src/main/java に
- jarに含めたいその他のリソース(設定ファイルとかそういうの)は src/main/resources に置く
- java のSystem.out.println 相当
このプログラムのエントリーポイントとなる部分のおまじない(と今は思っておいて)
ターミナルで scala と打つとREPL(Read Eval Print Loop)が立ち上がるので対話的にScalaが実行できる
scala コマンドに *.scala
を食わせるとスクリプトとして実行できる
""
で囲むと文字列(String
)となる。数字はそのまま書くとInt
になる。数字のあとにl
を付けるとLong
。少数を普通に書くとDouble
。''
で文字を囲むとChar
となる。true
, false
が Boolean
。プリミティブ型ってのはなくてすべてがオブジェクト。
object Main {
def main(args: Array[String]) = {
val hello = "hello scala" //型宣言がない!
println(hello)
val hello2: String = "hello!" //型宣言しようと思えばできる
println(hello2)
// hello2 = "wrong!!" //val で宣言した変数には再代入ができない
var hello3 = "hello scala!!"
println(hello3)
hello3 = "hello scala!!!" // varで宣言した変数には再代入ができる
println(hello3)
hello3 = 123 // 型が違うので代入できない
var hello4:Any = "hoge"
hello4 = 123 // String is a Any だし Int is a Any なので代入可能
}
}
class Player {
val name = "しんぺい"
var hp = 10
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player
println(shinpei.name)
println(shinpei.hp)
shinpei.hp = 4 // var なので代入できる
println(shinpei.hp)
}
}
public なフィールドを定義しているように見えるけど、内部的にはアクセサを自動で生成してる。今後はこれを便宜的に「publicなプロパティ」と呼ぶ
privateにしてみる
class Player {
val name = "しんぺい"
private var hp = 10
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player
println(shinpei.name)
println(shinpei.hp) //コンパイルエラー
shinpei.hp = 4 //コンパイルエラー
println(shinpei.hp) //コンパイルエラー
}
}
// 引数の型は必ず指定する
class Player(_name: String) {
// _name は private field扱いになるので外部に公開するために代入する
val name = _name
private var hp = 10
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい")
val takashi = new Player("たかし")
println(shinpei.name)
println(takashi.name)
}
}
あるいは
//コンストラクタのパラメータにval とかvar を付けるとパブリックなプロパティ扱いになる
class Player(val name: String) {
private var hp = 10
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい")
val takashi = new Player("たかし")
println(shinpei.name)
println(takashi.name)
}
}
// private とかつければそうなる
class Player(val name: String, private var hp: Int = 10)
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい")
val takashi = new Player("たかし")
println(shinpei.name)
println(takashi.name)
}
}
class Player(val name: String, private var hp: Int = 10) {
// 引数の型は必ず指定しなければならない
// メソッドはデフォルトで public となる
// 返り値の型は省略可能
def attack(otherPlayer: Player) = println(name + "は" + otherPlayer.name + "を攻撃した!")
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい")
val takashi = new Player("たかし")
takashi.attack(shinpei)
}
}
返り値の型を明示することもできる
class Player(val name: String, private var hp: Int = 10) {
// UnitはJavaでいうところのvoid
def attack(otherPlayer: Player): Unit = println(name + "は" + otherPlayer.name + "を攻撃した!")
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい")
val takashi = new Player("たかし")
takashi.attack(shinpei)
}
}
class Player(val name: String, private var hp: Int = 10) {
// 複数行に渡るメソッドは {} で囲む
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
otherPlayer.damaged(3)
}
def damaged(damage: Int): Unit = {
println(name + "は" + damage.toString + "のダメージを受けた")
// if が値を返している。
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) { println(name + "は死んでしまった" }
}
// return はいらない
private def isDead: Boolean = hp <= 0
}
object Main {
def main(args: Array[String]) = {
val shinpei = new Player("しんぺい", 3)
val takashi = new Player("たかし")
takashi.attack(shinpei)
}
}
クラスメソッドってのは存在しない。それっぽい見た目のものは定義できる。
// Playerという名前のシングルトンオブジェクトを定義している。
// 初めて参照されたときにインスタンス化され、
// 二度目以降はそのインスタンスを参照する
object Player {
val defaultPlayreName = "名無しマン"
def createDefaultPlayer = new Player(defaultPlayerName)
}
class Player(val name: String, private var hp: Int = 10) {
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
otherPlayer.damaged(3)
}
def damaged(damage: Int): Unit = {
println(name + "は" + damage.toString + "のダメージを受けた")
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) { println(name + "は死んでしまった" }
}
private def isDead: Boolean = hp <= 0
}
object Main {
def main(args: Array[String]) = {
val shinpei = Player.defaultPlayer
val takashi = new Player("たかし")
}
}
extends でできます
class Player(val name: String, private var hp: Int = 10) {
val strength = 3
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
otherPlayer.damaged(strength)
}
def damaged(damage: Int) = {
println(name + "は" + damage.toString + "のダメージを受けた")
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) { println(name + "は死んでしまった") }
}
private def isDead = hp <= 0
}
class Knight(name: String, hp: Int) extends Player(name: String, hp: Int) {
override val strength = 5
}
class Magician(name: String, hp: Int, private var mp: Int = 5) extends Player(name: String, hp:Int) {
def mera(otherPlayer: Player) = {
println(name + "はメラを唱えた")
if (mp < 3) {
"しかしmpが足りない"
} else {
mp -= 3
otherPlayer.damaged(10)
}
}
}
object Main {
def main(args: Array[String]): Unit = {
val shinpei = new Magician("しんぺい", 10, 5)
val takashi = new Knight("たかし",15)
shinpei.mera(takashi)
takashi.attack(shinpei)
takashi.attack(shinpei)
}
}
traitというのがそれです。実装も書けてマジクール。Java の インターフェイス と Ruby の Moduleの中間みたいな
trait Weapon {
val strength: Int
}
trait KnightWeapon extends Weapon
trait MagicianWeapon extends Weapon
object NullWeapon extends Weapon {
val strength = 0
}
object LongSword extends KnightWeapon {
val strength = 10
}
object Rod extends MagicianWeapon {
val strength = 2
}
trait HasWeapon {
protected var weapon: Weapon = NullWeapon
}
trait CanEquipKnightWeapon extends HasWeapon {
def equip(w: KnightWeapon) = weapon = w
}
trait CanEquipMagicianWeapon extends HasWeapon {
def equip(w: MagicianWeapon) = weapon = w
}
class Player(val name: String, private var hp: Int = 10) extends HasWeapon {
val strength = 3
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
val damage = strength + weapon.strength
otherPlayer.damaged(damage)
}
def damaged(damage: Int) = {
println(name + "は" + damage.toString + "のダメージを受けた")
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) {
println(name + "は死んでしまった")
}
}
private def isDead = hp <= 0
}
class Knight(name: String, hp: Int)
extends Player(name: String, hp: Int) with CanEquipKnightWeapon {
override val strength = 5
}
class Magician(name: String, hp: Int, private var mp: Int = 5)
extends Player(name: String, hp:Int) with CanEquipMagicianWeapon {
def mera(otherPlayer: Player) = {
println(name + "はメラを唱えた")
if (mp < 3) {
"しかしmpが足りない"
} else {
otherPlayer.damaged(10)
}
}
}
object Main {
def main(args: Array[String]): Unit = {
val shinpei = new Magician("しんぺい", 10, 5)
val takashi = new Knight("たかし",15)
shinpei.equip(Rod)
shinpei.attack(takashi)
takashi.equip(LongSword)
takashi.attack(shinpei)
}
}
ところで、CanEquiq**Weapon、DRYじゃなくて気になる。型パラメータ使おう。
trait Weapon {
val strength: Int
}
trait KnightWeapon extends Weapon
trait MagicianWeapon extends Weapon
object NullWeapon extends Weapon {
val strength = 0
}
object LongSword extends KnightWeapon {
val strength = 10
}
object Rod extends MagicianWeapon {
val strength = 2
}
trait HasWeapon {
protected var weapon: Weapon = NullWeapon
}
trait CanEquip[T <: Weapon] extends HasWeapon {
def equip(w: T) = weapon = w
}
class Player(val name: String, private var hp: Int = 10) extends HasWeapon {
val strength = 3
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
val damage = strength + weapon.strength
otherPlayer.damaged(damage)
}
def damaged(damage: Int) = {
println(name + "は" + damage.toString + "のダメージを受けた")
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) {
println(name + "は死んでしまった")
}
}
private def isDead = hp <= 0
}
class Knight(name: String, hp: Int)
extends Player(name: String, hp: Int) with CanEquip[KnightWeapon] {
override val strength = 5
}
class Magician(name: String, hp: Int, private var mp: Int = 5)
extends Player(name: String, hp:Int) with CanEquip[MagicianWeapon] {
def mera(otherPlayer: Player) = {
println(name + "はメラを唱えた")
if (mp < 3) {
"しかしmpが足りない"
} else {
otherPlayer.damaged(10)
}
}
}
object Main {
def main(args: Array[String]): Unit = {
val shinpei = new Magician("しんぺい", 10, 5)
val takashi = new Knight("たかし",15)
shinpei.equip(Rod)
shinpei.attack(takashi)
takashi.equip(LongSword)
takashi.attack(shinpei)
}
}
ちなみに、クラス定義のときじゃなくて new するときにも trait を mixin できる
trait Weapon {
val strength: Int
}
trait KnightWeapon extends Weapon
trait MagicianWeapon extends Weapon
object NullWeapon extends Weapon {
val strength = 0
}
object LongSword extends KnightWeapon {
val strength = 10
}
object Rod extends MagicianWeapon {
val strength = 2
}
trait HasWeapon {
protected var weapon: Weapon = NullWeapon
}
trait CanEquip[T <: Weapon] extends HasWeapon {
def equip(w: T) = weapon = w
}
class Player(val name: String, private var hp: Int = 10) extends HasWeapon {
val strength = 3
def attack(otherPlayer: Player): Unit = {
println(name + "は" + otherPlayer.name + "を攻撃した!")
val damage = strength + weapon.strength
otherPlayer.damaged(damage)
}
def damaged(damage: Int) = {
println(name + "は" + damage.toString + "のダメージを受けた")
hp = if (hp - damage < 0) { 0 } else { hp - damage }
if (isDead) {
println(name + "は死んでしまった")
}
}
private def isDead = hp <= 0
}
class Knight(name: String, hp: Int)
extends Player(name: String, hp: Int) with CanEquip[KnightWeapon] {
override val strength = 5
}
class Magician(name: String, hp: Int, private var mp: Int = 5)
extends Player(name: String, hp:Int) with CanEquip[MagicianWeapon] {
def mera(otherPlayer: Player) = {
println(name + "はメラを唱えた")
if (mp < 3) {
"しかしmpが足りない"
} else {
otherPlayer.damaged(10)
}
}
}
object Main {
def main(args: Array[String]): Unit = {
val shinpei = new Magician("しんぺい", 10, 5)
val takashi = new Player("たかし",15) with CanEquip[Weapon]
shinpei.equip(Rod)
shinpei.attack(takashi)
takashi.equip(LongSword)
takashi.attack(shinpei)
}
}
のところは、var hp: Int みたいに型指定が必要ですよね。