はじめに
最近のKotlinの動向は熱いですよね。
特にAndroidの公式な開発言語になったことと、Spring 5が公式サポートしたことはインパクトがあり、私もKotlinの学習を始めました。
この記事は私のような「Kotlinが気になっているSwiftプログラマー」向けです。
Apple公式のSwiftチュートリアル A Swift Tour を、Kotlinで書き替えてみました。
長くなったので記事を分けました。
第一回(この記事)
・シンプルな値
・制御フロー
・関数とクロージャー
第二回
・クラス
・列挙体
・構造体
・プロトコル(インターフェイス)
・拡張
前提バージョン
- Swift 4
- Kotlin 1.1
Hello, World!
print("Hello, world!")
fun main(args: Array<String>) {
println("Hello, world!")
}
どちらも;
は不要です。私は素敵だと思います。
シンプルな値
変数と定数
var myVariable = 42
myVariable = 50
let myConstant = 42
var myVariable = 42
myVariable = 50
val myConstant = 42
定数(再代入できない変数)は、Kotlinはval
。
型推論と型宣言
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
val implicitInteger = 70
val implicitDouble = 70.0
val explicitDouble: Double = 70.0
近年開発された言語では、型宣言は後置が主流みたいですね。
Kotlinのデータ型についてはこちら。
Kotlin Reference -Basic-Types
明示的な型変換
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
val label = "The width is "
val width = 94
val widthLabel = label + width.toString()
Kotlinは、val widthLabel = label + width
でもOKです。
Swiftとの比較のため、あえて上のように書きました。
文字列への変数の埋め込み
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
val apples = 3
val oranges = 5
val appleSummary = "I have ${apples} apples."
val fruitSummary = "I have ${apples + oranges} pieces of fruit."
複数の行を使用する文字列
let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""
val quotation = """
I said "I have ${apples} apples."
And then I said "I have ${apples + oranges} pieces of fruit."
"""
コレクション
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
print(shoppingList) // ["catfish", "bottle of water", "tulips", "blue paint"]
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
print(occupations) // ["Malcolm": "Captain", "Jayne": "Public Relations", "Kaylee": "Mechanic"]
var shoppingList = mutableListOf("catfish", "water", "tulips", "blue paint")
shoppingList.set(1, "bottle of water")
println(shoppingList) // [catfish, bottle of water, tulips, blue paint]
var occupations = mutableMapOf(
"Malcolm" to "Captain",
"Kaylee" to "Mechanic"
)
occupations.set("Jayne", "Public Relations")
println(occupations) // {Malcolm=Captain", Kaylee=Mechanic, Jayne=Public Relations}
Kotlinのコレクションは仕様的にJVMの制約を引きずっているようですし、JavaのコレクションAPIも使えるので、使いこなすにはそれなりの学習が必要そうです。
Kotlin Reference -Collections
Kotlinコレクション入門
制御フロー
forループとif文
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore) // 11
val individualScores = listOf(75, 43, 103, 87, 12)
var teamScore = 0
for (score in individualScores) {
if (score > 50) {
teamScore += 3
} else {
teamScore += 1
}
}
println(teamScore) // 11
Kotlinの条件式は( )
が必須です。
SwiftもKotlinもCスタイルのループfor (Int i = 0; i < n; i++)
は廃止されています。
Swiftはi++
、++i
、i--
、--i
の演算子は廃止されていますが、Kotlinでは使えます。
while文
var n = 2
while n < 100 {
n *= 2
}
print(n) // 128
var m = 2
repeat {
m *= 2
} while m < 100
print(m) // 128
var n = 2
while (n < 100) {
n *= 2
}
println(n) // 128
var m = 2
do {
m *= 2
} while (m < 100)
println(m) // 128
Null Safety
var optionalString: String? = "Hello"
print(optionalString == nil) // false
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
println(greeting) // Hello, John Appleseed
}
var optionalString: String? = "Hello"
println(optionalString == null) // false
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
optionalName?.let {
val name = it
greeting = "Hello, ${name}"
print(greeting) // Hello, John Appleseed
}
SwiftのOptionalはKotlinではNullableと呼びます。
Kotlinのit
はなかなかイケてると思いました。
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"
print(informalGreeting) // Hi John Appleseed
val nickName: String? = null
val fullName: String = "John Appleseed"
val informalGreeting = "Hi ${nickName ?: fullName}"
println(informalGreeting) // Hi John Appleseed
Kotlinコードの?:
はElvis構文と呼びます。
switch文
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
// Is it a spicy red pepper?
val vegetable = "red pepper"
when (vegetable) {
"celery" ->
println("Add some raisins and make ants on a log.")
"cucumber", "watercress" ->
println("That would make a good tea sandwich.")
else -> {
if (vegetable.endsWith("pepper")) {
println("Is it a spicy ${vegetable}?")
} else {
println("Everything tastes good in soup.")
}
}
}
Kotlinのswitch文は、Swiftほどは、多種多様な比較演算をサポートしていないようです。
KotlinもSwiftと同様に、Javaのようにbreak;
を書かなくてもフォールスルーしません。
コードが簡潔になって良いですよね。
関数とクロージャー
関数の基本構文
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
print(greet(person: "Bob", day: "Tuesday")) // Hello Bob, today is Tuesday.
fun greet(person: String, day: String): String {
return "Hello ${person}, today is ${day}."
}
println(greet(person = "Bob", day = "Tuesday")) // Hello Bob, today is Tuesday.
Kotlinも名前付きパラメータを取り入れています。
パラメータ名を省略する場合、Swiftでは関数側で_
によって省略することを宣言しますが、Kotlinでは、以下のように呼び元側で省略します。
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
print(greet("John", on: "Wednesday")) // Hello John, today is Wednesday.
fun greet(person: String, day: String): String {
return "Hello ${person}, today is ${day}."
}
println(greet("Bob", day = "Tuesday")) // Hello Bob, today is Tuesday.
Swiftはパラメータ変数名と引数のラベルを別の名前にできますが、Kotlinにはその機能はないようです。
タプル
Kotlinでは古いバージョンにはタプルがあったようですが、バージョンアップ時に削除されたとのこと。
(参考)https://blog.jetbrains.com/kotlin/2016/12/kotlin-1-1-m04-is-here/
値が2つだけのPair
という形では残っています。
Kotlin -Pair
関数のネスト
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
print(returnFifteen()) // 15
fun returnFifteen() : Int {
var y = 10
fun add() {
y += 5
}
add()
return y
}
println(returnFifteen()) // 15
どちらも、内部関数から外部関数のローカル変数(つまりクロージャ)に対し演算することができます。
高階関数
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: {(number: Int) -> Bool in return number < 10})
// true
fun hasAnyMatches(list: List<Int>, condition: (Int) -> Boolean) : Boolean {
for (item in list) {
if (condition(item)) {
return true
}
}
return false
}
var numbers = listOf(20, 19, 7, 12)
hasAnyMatches(list = numbers, condition = fun(number: Int) : Boolean {return number < 10})
// true
どちらも関数は第一級オブジェクトです。
関数の引数で無名関数を渡したり、戻り値として関数を受け取ったりは、どちらでもシンプルに書けます。
第二回はこちらです。
SwiftとKotlinの構文比較 (2) 〜クラス、列挙体、構造体、プロトコル、拡張