🔖

【Swift Concurrency】引数に付与するsendingキーワードについて

2024/10/13に公開

引数に付与するsendingキーワード

現在sendingキーワードは、「引数に付与するケース」と「返り値に付与するケース」があります。本記事では、引数に付与する場合のsendingキーワードについて解説していきます。

引数に付与するsendingキーワードは、「関数がnon-Sendableな値を引数として受け取るときに、その値が呼び出し元で引き渡し後に使用されないこと」を保証させるキーワードです。

これにより、引数として受け取ったnon-Sendableな値が隔離境界(isolation boundary)を超えることができるようになります。[1]

以下のコードでは、action2関数内でNonSendableClassのインスタンスを生成し、action1関数の引数として、生成したインスタンスを渡しています。

class NonSendableClass { var num = 0 }

func action1(nonSendableClass: sending NonSendableClass) {
    Task { @MainActor in
        print(nonSendableClass)
    }
}

func action2() {
    let nonSendableClass = NonSendableClass()
    action1(nonSendableClass: nonSendableClass)
}

action1関数の引数として受け取るNonSendableClassのインスタンスは、action1関数内でnon-isolatedな隔離領域からMainActorの隔離領域に渡ります。(つまりは隔離境界を超える。)

そのため、「関数がnon-Sendableな値を引数として受け取るときに、その値が呼び出し元で引き渡し後に使用されないこと」を保証させるsendingキーワードが必要です。

蛇足

もし、以下コードのように引き渡し後にnonSendableClassにアクセスした場合は、エラーで教えてくれます。

class NonSendableClass { var num = 0 }

func action1(nonSendableClass: sending NonSendableClass) {
    Task { @MainActor in
        print(nonSendableClass)
    }
}

func action2() {
    let nonSendableClass = NonSendableClass()
    action1(nonSendableClass: nonSendableClass) // ※1
    print(nonSendableClass) // nonSendableClassにアクセス
}

// ※1: Sending 'nonSendableClass' risks causing data races

参考

Xcode 16 & Swift 6 キャッチアップ: Swift Concurrencyの基礎と最重要ポイントを総復習 - YouTube

https://www.youtube.com/watch?v=jJgEtjx8KHY

swift-evolution/proposals/0430-transferring-parameters-and-results.md at main · swiftlang/swift-evolution · GitHub

https://github.com/swiftlang/swift-evolution/blob/main/proposals/0430-transferring-parameters-and-results.md

脚注
  1. このような隔離境界を超えることができる値をsending valueと呼びます。 ↩︎

Discussion