前回に引き続きSwiftエンジニアがKotlinのチュートリアルを進めます。今回はBasic syntax walk-throughの章です。
http://try.kotlinlang.org/#/Examples/Basic%20syntax%20walk-through/Use%20a%20conditional%20expression/Use%20a%20conditional%20expression.kt
自分が実装した分のリポジトリ
https://github.com/akatsuki174/KotlinTutorial
上記のBasicSyntaxWalkThrough.ktファイル
Basic syntax walk-through
Use a conditional expression
ここではif
の使い方と関数の使い方が学べます。
fun max(a: Int, b: Int) = if (a > b) a else b
ifに関しては前回の記事にも書いたので省略します。関数についてですが、以下のことについては今までのチュートリアルでも学んだことです。
- 関数宣言は
fun
であること - selfなどなしに呼び出せること
今回はそれに加え単一式関数の記法が出てきました。単一の値を返すだけであれば=
で繋いで1行で書くことができます。また、型推論ができる場合には戻り値の型を指定する必要はありません。ということで、以下のような書き方も可能です。
// 戻り値の型を指定
fun max(a: Int, b: Int):Int = if (a > b) a else b
// ブロックを使用
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
引数については名前:タイプ
の順で書かれること、引数を複数持つ場合はカンマで区切るということがわかります。また、Javaとは異なり名前付き引数を使うこともできます。今回の例の場合だと、次のように書くことができます。
max(a = args[0].toInt(), b = args[1].toInt())
ifに関しての公式資料はこちら
単一式関数に関しての公式資料はこちら
Null-checks
fun main(args: Array<String>) {
if (args.size < 2) {
println("No number supplied");
} else {
val x = parseInt(args[0])
val y = parseInt(args[1])
// x,yにnullが入っている可能性がある
if (x != null && y != null) {
print(x * y)
} else {
println("One of the arguments is null")
}
}
}
// もしstrが数字ではなかったらnullを返す
fun parseInt(str: String): Int? {
try {
return str.toInt()
} catch (e: NumberFormatException) {
println("One of the arguments isn't Int")
}
return null
}
JavaではnullオブジェクトにアクセスするとNullPointerExceptionが発生していました。KotlinはコードからNullPointerExceptionが発生しないように作られています。NullPointerExceptionが発生するのは以下の状態の時です。
- 明示的に
throw NullPointerException()
をした時 - 一定条件下で
!!
を使った時 - 外部のJavaコードがNullPointerExceptionになった時
- 初期化の際のデータ不備(初期化されていないのにどこかで使われている)
Swiftのように、ある変数がnullになりうる場合は「?」を付けてそれを明示しなければなりません。
「安全でない」場合は以下のような表示が出ます。
null安全に関する公式資料はこちら
is-checks and smart casts
fun main(args: Array<String>) {
println(getStringLength("aaa"))
println(getStringLength(1))
}
fun getStringLength(obj: Any): Int? {
if (obj is String)
return obj.length // no cast to String is needed
return null
}
is
は型チェックを行うことができ、否定型は!is
になります。
is
で型チェックを行うと自動的にキャストが行われるため、上の例でもobj
は型チェック後すぐにString型として使えています。公式に例として載っている以下のコードはとてもクールだと思います。
if (x !is String) return
print(x.length) // x is automatically cast to String
また以下のようなコードも書けます。型チェック後すぐにString型として使うことができています。
if (x !is String || x.length == 0) return
when
との組み合わせでも使われます。
when (x) {
is Int -> print(x + 1)
}
クラスと継承に関する公式資料はこちら
スマートキャストに関する公式資料はこちら
Use a while-loop
fun main(args: Array<String>) {
var i = 0
while (i < args.size)
println(args[i++])
}
while
とdo..while
の書き方を学ぶサンプルになります。do.while
で書く場合はこのような形を取ります。
do {
println(args[i++])
} while (i < args.size)
whileループに関する公式資料はこちら
Use a for-loop
fun main(args: Array<String>) {
for (arg in args)
println(arg)
println()
for (i in args.indices)
println(args[i])
}
今度はforループの使い方についてです。前回の記事でも書いた通り、このような書き方もできます。
for ((index, value) in args.withIndex())
println("$index: value is $value")
forループに関する公式資料はこちら
Use ranges and in
fun main(args: Array<String>) {
val x = args[0].toInt()
// xがある範囲内に入っているか確認
val y = 10
if (x in 1..y - 1)
println("OK")
//範囲内で繰り返し
for (a in 1..5)
print("${a} ")
println()
val array = arrayListOf<String>()
array.add("aaa")
array.add("bbb")
array.add("ccc")
// ある数値が範囲外か確認
if (x !in 0..array.size - 1)
println("Out: array has only ${array.size} elements. x = ${x}")
// コレクションがあるオブジェクトを含むか確認
if ("aaa" in array) // collection.contains(obj) is called
println("Yes: array contains aaa")
if ("ddd" in array) // collection.contains(obj) is called
println("Yes: array contains ddd")
else
println("No: array doesn't contains ddd")
}
range
, in
とともに使われることがある関数としてdownTo
、step
があり、以下のような使い方をします。
// 数を逆順に処理したければdownTo関数が使える
for (i in 5 downTo 1) print(i)
// xつごとに処理を実行したい場合はstep関数が使える
for (i in 1..4 step 2) print(i) // 2つごとに処理を実行
Rangeに関する公式資料はこちら
Use when
fun main(args: Array<String>) {
cases("Hello")
cases(1)
cases(0L)
cases(MyClass())
cases("hello")
}
fun cases(obj: Any) {
when (obj) {
1 -> println("One")
"Hello" -> println("Greeting")
is Long -> println("Long")
!is String -> println("Not a string")
else -> println("Unknown")
}
}
class MyClass() {
}
whenに関しては前回の記事でも書いたのでさらっと書きます。switch
文のような形で使うことができます。条件を満たすものが現れるまで評価し続けます。is
を使って型判定も行うことができます。
感想
名前付き引数があるので読みやすい
Javaとは異なり引数に名前を付けられるのは読みやすくていいなと思います。ただ引数の名前は任意であるため、IntelliJ IDEAで関数名を自動補完で入力した時に引数名も入力されないのは少し残念だなと思いました。
型周りが扱いやすい
↓これって結構すごいことだと思っています。
fun cases(obj: Any) {
when (obj) {
1 -> println("One")
"Hello" -> println("Greeting")
is Long -> println("Long")
else -> println("Unknown")
}
}
Swiftで同じように書こうとしてもできないですし(たぶん)。