0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Josh Skeen, David Greenhalgh著 『Kotlinプログラミング』 章末問題に挑戦(第13章)

Last updated at Posted at 2020-12-19

 Josh Skeen, David Greenhalgh著『Kotlinプログラミング』には章末問題がある。残念なことに解答がないので、第10章に引き続き本を読み進めながら答案を記述する。
 もし回答に間違いや意見があれば、ぜひご指摘いただきたい。

第13章 章末問題 回答案

13.7 チャレンジ! エクスカリバーの謎

 本書 リスト13-16,17の動作には少し悩んだので、復習を兼ねて次のコードを実行して初期化について挙動を確認した。(以下に示すD5クラス、D6クラスの動作が理解できていなかった。)
 ポイントはfiledキーワードとプロパティー、初期化ブロック(init{...})に与えられた値の関係、挙動を理解することだと思います。コード横にコメントを記入しましたが、うまく説明ができませんでしたので、以下のコードをコンパイルして動作を確認してください。

C1クラス

C1.kt
fun main() {
    // クラスC1のプロパティを呼び出す
    println()
    println("C1をインスタンス化")
    val c1 = C1()
    println("クラスC1インスタンス直後のpropty: ${c1.propty}")    // abc
}

// ゲッター・セッターなし(ゲッター機能あり、セッター機能なし)
class C1 {
    val propty = "abc"
}

C2クラス

C2.kt
fun main() {
    // クラスC2のプロパティに書き込み、それを呼び出す
    println()
    println("C2をインスタンス化")
    var c2 = C2()   // 書き換えをするため変数定義のキーワードをvalからvarに変更
    println("クラスC2インスタンス直後のpropty: ${c2.propty}")    // abc
    c2.propty = "def"
    println("C2のpropty: ${c2.propty}")   // def
}

// クラスプロパティにゲッターセッターを追加する
class C2 {
    var propty = "abc"  // 書き換えをするため変数定義のキーワードをvalからvarに変更
        get() = field   // fieldは、この場合、proptyのことである
        set(value) {    // valueは、この場合、セッターによって受け取る値である
            field = value
        }
}

C3クラス

C3.kt
fun main() {
    // クラスC3のコンストラクタを用いて初期値を与える
    println()
    println("コンストラクタを用いてプロパティに初期値ghiを与える")
    var c3 = C3("ghi")
    println("クラスC3のpropty: ${c3.propty}")    // ghi
    println("クラスC3のproptyをセッターを用いてdefに書き換える")
    c3.propty = "def"
    println("クラスC3のpropty: ${c3.propty}")    // def
    println()
}

// クラスコンストラクタを追加する
class C3(_propty: String){  // _proptyはこの波括弧{...}内をスコープとする使い捨ての変数
    var propty = _propty    // コンストラクタを使ってコンストラクタで与えられた値_proptyを使って、proptyを初期化
        get() = field       // c3.proptyを要求された時に、filedを通してproptyの値が出力される
        set(value) {        // c3.propty="xxx"で値が与えられたときに、valueがxxxという値になり、fieldに値が渡される。このときfieldはproptyのことである。
            field = value
        }
}

D1クラス

D1.kt
fun main() {
    println()
    println("D1をインスタンス化")
    val d1 = D1()
    println("クラスD1インスタンス化直後に、ゲッターを通して得たpropty: ${d1.propty}")   // Abc
}

// abcという文字列の先頭文字を大文字に変えて、proptyに与える。
class D1 {
    val propty = "abc".capitalize()
}

D2クラス

D2.kt
fun main() {
    //
    println()
    println("D2をインスタンス化")
    var d2 = D2()   // 書き換えをするため変数定義のキーワードをvalからvarに変更
    println("クラスD2インスタンス化直後に、ゲッターを通して得たpropty: ${d2.propty}")   // Abc
    d2.propty = "mno"
    println("D2のセッターにmnoを与えた直後に、ゲッターを通して得たpropty: ${d2.propty}")   // Mnodef
}

// クラスプロパティにゲッターセッターを追加する
class D2 {
    var propty = "abc"
        get() = field.capitalize()  // fieldはproptyを示し、この値を加工し、get()で出力する
        set(value) {
            field = value + "def"   // セッターで受け取った値をvalueを通して加工して(この場合、valueにdefを加えて)、field(この場合propty)に渡す。
        }
}

D3クラス

D3.kt
fun main() {
    //
    println()
    println("D3のプライマリコンストラクタにjklを与えインスタンス化")
    var d3 = D3("jkl")
    println("クラスD3インスタンス化直後に、ゲッターを通して得たpropty: ${d3.propty}")   // Jkl
    d3.propty = "mno"
    println("D3のセッターにmnoを与えた直後に、ゲッターを通して得たpropty: ${d3.propty}")   // Mnodef
}

// クラスに引数ありのプライマリコンストラクタを追加する
class D3(_propty: String) {
    var propty = _propty    // コンストラクタを通して得た値_proptyをproptyに与える
        get() = field.capitalize()
        set(value) {
            field = value + "def"
        }
}

D4クラス

D4.kt
fun main() {
    //
    println()
    println("D4コンストラクタにjklを与えインスタンス化")
    var d4 = D4("jkl")
    println("クラスD4インスタンス化直後に、ゲッターを通して得たpropty: ${d4.propty}")   // Abc
    d4.propty = "mno"
    println("D4のセッターにmnoを与えた直後に、ゲッターを通して得たpropty: ${d4.propty}")   // Mnodef

}
// 引数ありコンストラクタではあるが、受け取った_proptyはproptyに与えることなく、proptyにはabcを与える
class D4(_propty: String) {
    var propty = "abc"  // proptyにabcを与える
        get() = field.capitalize()
        set(value) {
            field = value + "def"
        }
}

D5クラス

D5.kt
fun main() {
    //
    println()
    println("D5のプライマリコンストラクタにjklを与えインスタンス化")
    var d5 = D5("jkl")
    println("クラスD5インスタンス化直後に、ゲッターを通して得たpropty: ${d5.propty}")   // Jkldef
    d5.propty = "mno"
    println("D5のセッターにmnoを与えた直後に、ゲッターを通して得たpropty: ${d5.propty}")   // Mnodef

    //
    println()
    println("D5 引数なしセカンドコンストラクタをインスタンス化")
    var d51 = D5()
    println("クラスD4(引数なしコンストラクタ)インスタンス化直後のプロパティ: ${d51.propty}")     // Ghidef
    d51.propty = "mno"
    println("D5のセッターにmnoを与えた直後のプロパティー: ${d51.propty}")      // Mnodef
}

// 初期化ブロックinit{...}を追加
class D5(_propty: String) {
    var propty = "abc"  // init初期化ブロックがあると、abcで初期化することはなく、
        // init{...}ブロックの中の式に従って動作する。
        get() = field.capitalize()
        set(value) {
            field = value + "def"
        }

    init{
        propty = _propty    // コンストラクタで与えられた値_proptyは、先ず直接proptyに代入されるのではなく、
        // proptyのセッターに与えられる。すなわちvalueが_proptyになり、
        // filedが_propty+"def"になり、最後にpropty(=filed)=_propty+"def"になる
        // この動きがinit{...}の挙動を理解する上での難点であった
    }

    constructor() : this("ghi")
}

D6クラス

D6.kt
fun main() {
    //
    println()
    println("D6のプライマリコンストラクタにjklを与えインスタンス化")
    var d6 = D6("jkl")
    println("クラスD6インスタンス化直後に、ゲッターを通して得たpropty: ${d6.propty}")   // Jkldef
    d6.propty = "mno"
    println("D5のセッターにmnoを与えた直後に、ゲッターを通して得たpropty: ${d6.propty}")   // Mnodef
}

// 初期化ブロックinit{...}を追加(D5クラスの"var propty ="で与える値が"abc"から_proptyに変更)
class D6(_propty: String) {
    var propty = _propty  // D6のプロパティーに_proptyを与えるが、この_proptyはこの行では何も寄与せず、
        // init{...}ブロックの中の式に従って動作する。
        get() = field.capitalize()
        set(value) {
            field = value + "def"
        }

    init{
        propty = _propty    // コンストラクタに与えられた値は、D5クラスのinit{...}と同じ動作をする。
    }

    constructor() : this("ghi")
}

第2章チャレンジ!答案
第3章チャレンジ!答案
第4章チャレンジ!答案
第7章チャレンジ!答案
第8章チャレンジ!答案
第10章チャレンジ!答案
第13章チャレンジ!答案
第15章チャレンジ!答案

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?