浅瀬でちゃぷちゃぷ Swift の学びのコーナー

Swift まったく書いたことない僕ですが、最近会社で余暇 (?) 先輩に iOS 開発学習を赤ちゃん用の浅いビニールプールでぱちゃぱちゃ泳がせてもらうかんじで初学者としてたのしく学んでいる。

そのときに教えてもらってユニークでおもしろかったのをメモしておいたので、記念にかいておこうとおもうよ〜〜数年後恥ずかしくなって削除できてると成長が実感できるというしくみになっている。そもそもこの記事の理解も死ぬほど曲解しててすでに大変なことになってるかもしれないけどそういう💣爆弾をたのしんでいきましょう人生🤪

KeyPath

Swift でまずびっくりしたのが KeyPath ってやつ。

qiita.com

プロパティまでの参照を定義して適用できるのおもしろ! という感じ。ユニーク。使ってみたくなるふしぎな魅力がありますな。class でも KeyPath が使えるのが面白い。

struct MyStruct {
    var a: Int
    var b: Int
}

var ms = MyStruct(a: 10, b: 20)
let msaPath = \MyStruct.a
let msbPath = \MyStruct.b

print("ms.a: \(ms[keyPath: msaPath])")
print("ms.b: \(ms[keyPath: msbPath])")

ms[keyPath: msaPath] = 111
ms[keyPath: msbPath] = 222

print("ms.a: \(ms.a)")
print("ms.b: \(ms.b)")

↑ でもこの例は KeyPath 1 ミリもわかってないやつの例というかんじがしておそれいりますね……🫢

C の構造体のベースのアドレスからポインタをサイズ分移動させたらメンバーを参照できたりする (パディングを考えなければ) やつをおもいだした:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct MyStruct {
    uint64_t a;
    uint64_t b;
} __attribute__((packed)) MyStruct;

int main(void) {
    MyStruct ms;
    MyStruct *pms = &ms;
    ms.a = 10;
    ms.b = 20;

    uint64_t *msa = ((void *)pms);
    uint64_t *msb = ((void *)pms + sizeof(uint64_t));

    printf("msa: %" PRIu64 "\n", *msa);
    printf("msb: %" PRIu64 "\n", *msb);
    
    *msa = 111;
    *msb = 222;
    
    printf("ms.a: %" PRIu64 "\n", ms.a);
    printf("ms.b: %" PRIu64 "\n", ms.b);
}
msa: 10
msb: 20
ms.a: 111
ms.b: 222

使いどころきいた記憶があるのだけど忘れてしまってなんだっけ……となっているけど、いろいろありそうであった:

qiita.com

引数のラベル

つけられるのはよくあるとして、つけないとダメなのとつけるとよくないときがあっておもしろい:

func f(_ a: Int, _ b: Int, c: String) {
    print("a = \(a), b = \(b), c = \(c)")
}

f(1, 2, c: "string")
// f(1, b: 2, c: "string") とすると怒られる
// f(1, 2, "string") としても怒られる)

Kotlin だとつけちゃダメみたいなのがないので、 つけたら怒られるのがおもしろい。絶対なにか理由があると思う。Python にもこういうのがありますな。

使い分け的などういう慣習でつけたりつけてなかったりするのかはわかってない。

resultBuilder

qiita.com

ブロックを書いて中で構築したりするのにいい感じの仕組みだと認識してるけどむずかしいらしい。

Kotlin だと trailing closure を駆使してビルダーを書いたりするわけだけど そういう感じのもの?

とも思ったんだけど、Swift でも trailing closure ってあるから、なにかもっと便利なのでしょうな

digitalnauts.com

guard

これを先頭で使ってガード節を書くと Swift っぽいとのこと:

func f(_ word: String) {
    guard !word.isEmpty else {
        return
    }
    print("word = \(word)")
}

f("hello")
f("")
f("friend")

きっとやっていくとその理由がわかるのだと思う。

struct, mutating func

これ Kotlin で考えたら let でいいじゃんとおもったらダメなやつがあって、なんで? と思ったら structmutating func とかの兼ね合いでムリというような事情があるようだった。

qiita.com

struct S {
    var a: Int

    mutating func mutate() {
        a += 10
    }
}

class K {
    var a: Int
    
    init(a: Int) {
        self.a = a
    }
    
    func mutate() {
        a += 10
    }
}

var s = S(a: 10) // let だとだめ
s.mutate()
print("s.a = \(s.a)")

let k = K(a: 10)
k.mutate()
print("k.a = \(k.a)")

なんで class だといいんだろ……。なにか理由があるんでしょうな。

C++const にちょっと通じるものがあるなとおもった。structclass があるのもにてるかんじがありますよね。C++structclass ってデフォルトのアクセス指定子 が privatepublic かとかの違いがあるくらいだったという記憶がある。

#include <iostream>

class Klass {
public:
    void fn1() const {
        std::cout << this << ": fn1" << std::endl;
    }

    void fn2() {
        std::cout << this << ": fn2" << std::endl;
    }
};

int main(void){
    Klass k1;
    const Klass k2;
    
    k1.fn1();
    k1.fn2();
    
    k2.fn1();
    k2.fn2(); // これはコンパイルエラー
}
Main.cpp:22:5: error: 'this' argument to member function 'fn2' has type 'const Klass', but function is not marked const
    k2.fn2(); // これはコンパイルエラー
    ^~
Main.cpp:9:10: note: 'fn2' declared here
    void fn2() {
         ^
1 error generated.

言語の入門は異文化交流感がありつつ知った言語との似通った部分があって面白いので、ドライバーがまったく知らない言語でペアプロしたりすると面白いかもしれないですね。みなさん僕にあなたの好きな言語をおしえてみませんか。