post Image
SwiftとKotlinの構文比較 (2) 〜クラス、列挙体、構造体、プロトコル、拡張

この記事は私のような「Kotlinが気になっているSwiftプログラマー」向けです。
Apple公式のSwiftチュートリアル A Swift Tour を、Kotlinで書き替えてみました。

第二回のトピックはこちらです。
 ・クラス
 ・列挙体
 ・構造体
 ・プロトコル(インターフェイス)
 ・拡張

前回の記事をまだお読みでなければ、こちらもぜひ。
SwiftとKotlinの構文比較 (1) 〜シンプルな値、制御フロー、関数とクロージャー

クラス

コンストラクタ

Swift
class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
Kotlin
class NamedShape(name: String) {
    var numberOfSides: Int = 0
    var name: String = ""

    init {
        this.name = name
    }

    fun simpleDescription() : String {
        return "A shape with ${numberOfSides} sides."
    }
}

Kotlinは上のようなプライマリー・コンストラクタ宣言と、セカンダリー・コンストラクタ宣言で記法が異なります。
セカンダリー・コンストラクタはconstructor(引数名: 型名)という構文で宣言します。
ちょっと独特な感じがします。
Kotlin Refrence -Classes

継承

Swift
class Square: NamedShape {
    var sideLength: Double

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }

    func area() -> Double {
        return sideLength * sideLength
    }

    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
print(test.area()) // 27.04
print(test.simpleDescription()) // A square with sides of length 5.2.
Kotlin
class Square(sideLength: Double, name: String): NamedShape(name) {
    var sideLength: Double

    init {
        this.sideLength = sideLength
        numberOfSides = 4
    }

    fun area() : Double {
        return sideLength * sideLength
    }

    override fun simpleDescription() : String {
        return "A square with sides of length ${sideLength}."
    }
}

fun main(args: Array<String>) {
    val test = Square(sideLength = 5.2, name = "my test square")
    println(test.area()) // 27.0400000000000003
    println(test.simpleDescription()) // A square with sides of length 5.2.
}

Kotlinはスーパークラスでopen class NamedShape(name: String)というように明示的にopen宣言をしないと、継承やoverrideができません。
保守性を向上するための仕様でしょうね。なるほどな〜と思いました。

自分自身のインスタンスを示すキーワードはthisです。

プロパティ

SwiftとKotlinのプロパティ構文は良く似ています。

Swift
class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }

    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter) // 9.3
triangle.perimeter = 9.9
print(triangle.sideLength) // 3.3
Kotlin
class EquilateralTriangle(sideLength: Double, name: String): NamedShape(name) {
    var sideLength: Double = 0.0

    init {
        this.sideLength = sideLength
        numberOfSides = 3
    }

    var perimeter: Double
        get() {
            return 3.0 * sideLength
        }
        set(newValue) {
            sideLength = newValue / 3.0
        }

    override fun simpleDescription() : String {
        return "An equilateral triangle with sides of length ${sideLength}."
    }
}

fun main(args: Array<String>) {
    var triangle = EquilateralTriangle(sideLength = 3.1, name = "a triangle")
    println(triangle.perimeter) // 9.3
    triangle.perimeter = 9.9
    println(triangle.sideLength) // 3.3000000000000003
}

Kotlinはクラスに(Javaのような)フィールドを持つことはできません。
プロパティにバッキングフィールドが必要な場合、fieldという変数名で自動的にそれを提供してくれます。

Kotlin
var counter = 0 // イニシャライザの value はバッキングフィールドへ直に書き込まれる
  set(value) {
    if (value >= 0)
      field = value
  }

Kotlin Reference -Properties and Fields

列挙体

Swift
enum Rank: Int {
    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king
    func simpleDescription() -> String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}
let ace = Rank.ace
print(ace.rawValue) // 1
print(ace.simpleDescription()) // ace
Kotlin
enum class Rank(val rawValue: Int) {
    ace(1), 
    two(2), three(3), four(4), five(5), six(6), seven(7), eight(8), nine(9), ten(10),
    jack(11), queen(12), king(13);
    fun simpleDescription() : String {
        when(this) {
            ace ->
                return "ace"
            jack ->
                return "jack"
            queen ->
                return "queen"
            king ->
                return "king"
            else ->
                return rawValue.toString()
        }
    }
}

fun main(args: Array<String>) {
    val ace = Rank.ace
    println(ace.rawValue) // 1
    println(ace.simpleDescription()) // ace
}

SwiftはInt、Kotlinはクラスを実体としているということで、少々違いがあります。
Kotlinはenum定数にnameプロパティを持っており、例えば上のコードのreturn "ace"return ace.nameとしても同じ結果を得られます。
さらには、以下のようにも書けます。

Kotlin
        when(this) {
            ace, jack, queen, king ->
                return this.name
            else ->
                return rawValue.toString()
        }

構造体

Swift
struct Card {
    var rank: Rank
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three)
print(threeOfSpades.simpleDescription()) // The 3
Kotlin
data class Card(var rank: Rank) {
    fun simpleDescription() : String {
        return "The ${rank.simpleDescription()}"
    }
}

fun main(args: Array<String>) {
    val threeOfSpades = Card(rank = Rank.three)
    println(threeOfSpades.simpleDescription()) // The 3
}

Kotlinはclassにdata修飾子をつけます。

プロトコル(インターフェイス)

Swift
protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}
Kotlin
interface ExampleProtocol {
    var simpleDescription: String
    fun adjust()
}

Kotlinのインターフェイスも実装(デフォルト実装)を持てます。

拡張

Swift
extension Int {
    var simpleDescription: String {
        return "The number \(self)"
    }
}
print(7.simpleDescription) // The number 7
Kotlin
val Int.simpleDescription: String get() = "The number ${this}"

fun main(args: Array<String>) {
    println(7.simpleDescription) // The number 7
}

Swiftはクラスを拡張、Kotlinはメソッドやプロパティ単位で拡張します。
その関係上、Swiftでのextension クラス: プロトコルと同等の設計はKotlinではできません。

おわりに

SwiftとKotlinの構文は良く似ていて、どちらもシンプルでセーフティですよね。
どちらも書いていて楽しい言語だと感じます。
唯一の欠点はJavaを書くのが辛くなってしまうことです(笑)

なお、例外処理については、概念的な違いの理解が必要であり、構文比較だけでは意味がないと思われたため割愛しました。

参考リンク

Swift is NOT like Kotlin..?


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。