LoginSignup
1
2

Swift 5.9 可変長汎型 Variadic Genericsを使ってみる。

Last updated at Posted at 2024-02-25

要点

次の引数の数を変えたオーバーロードを

func query<Payload>(
    _ item: Request<Payload>
) -> Payload

func query<Payload1, Payload2>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>
) -> (Payload1, Payload2)

func query<Payload1, Payload2, Payload3>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>,
    _ item3: Request<Payload3>
) -> (Payload1, Payload2, Payload3)

func query<Payload1, Payload2, Payload3, Payload4>(
    _ item1: Request<Payload1>,
    _ item2: Request<Payload2>,
    _ item3: Request<Payload3>,
    _ item4: Request<Payload4>
) -> (Payload1, Payload2, Payload3, Payload4)

次のようにまとめられる。

func query<each Payload>(_ item: repeat Request<each Payload>) -> (repeat each Payload)

次のように使用すると上記のeach PayloadInt, String, Boolが順繰りに入る。

let results = query(Request<Int>(), Request<String>(), Request<Bool>())

上記コードはWWDC2023の動画から拝借。

  • each Payload は型引数パック (Type Parameter Pack)。英文法に照らしてeachの後は単数型が適切
  • itemは値引数パック (Value Parameter Pack)
  • repeatは繰返パターン(repetition pattern)。repeat each Payload の表記は、一連の具象型をコンマで区切ったInt, String, Boolのような表記に置き換わる。そのためTupleや関数宣言の括弧(...)の中でのみ使用ができる

実験

下記コードをplaygroundにコピペすると挙動を確認できます。
(Swift5.9, Xcode 15.2で動作確認済)

// MARK: Protocol

protocol MockProtocol {
    associatedtype Value
    var value: Value { get }
    var description: String { get }
}

extension MockProtocol {
    var description: String { "\(value)" }
}

// MARK: Basic Structs

struct MockString: MockProtocol {
    let value = "I am MockString"
}

struct MockInt: MockProtocol {
    let value = 1
}

struct MockBool: MockProtocol {
    let value = true
}

// MARK: Tuple Struct

struct MockTuple<each V: MockProtocol>: MockProtocol {
    let value: (repeat each V)

    init(_ value: repeat each V) {
        self.value = (repeat each value)
    }
}

extension MockTuple {
    var description: String {
        let descriptionTuple = (repeat (each value).description)
        return "\(descriptionTuple)"
    }
}

// Mark: Implementation

func returnMockTuple<each T: MockProtocol>(_ t: repeat each T) -> MockTuple<repeat each T> {
    return MockTuple(repeat each t) // MockTupleB<Pack{MockString, MockInt, MockBool}>
}

returnMockTuple(MockString(), MockInt(), MockBool()).description // "("I am MockString", "1", "true")"

参考資料

1
2
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
1
2