1.2K Views
January 23, 26
スライド概要
potatotips #94 iOS/Android開発Tips共有会の登壇資料です。
https://potatotips.connpass.com/event/376432/
SwiftとLEGOとBluetooth LEが好きなプログラマ
5分で慣れるVariadic Generics 大庭 慎一郎 @ooba / @bricklife
話している人 大庭 慎一郎(おおば しんいちろう) ID: @ooba / @bricklife SwiftとLEGOが好きなプログラマ メルカリ1人目のiOSアプリエンジニア
Variadic Generics 可変長ジェネリクス
Value and Type Parameter Packs SE-0393 Implemented (Swift 5.9)
protocol RequestProtocol {
associatedtype Input
associatedtype Output
}
func evaluate(_ input: Input) throws -> Output
struct Evaluator<each Request: RequestProtocol> {
var item: (repeat each Request)
}
func query(_ input: repeat (each Request).Input) -> (repeat (each Request).Output)? {
do {
return (repeat try (each item).evaluate(each input))
} catch {
return nil
}
}
出典: https://developer.apple.com/videos/play/wwdc2023/10168
protocol RequestProtocol {
associatedtype Input
associatedtype Output
}
func evaluate(_ input: Input) throws -> Output
struct Evaluator<each Request: RequestProtocol> {
var item: (repeat each Request)
}
func query(_ input: repeat (each Request).Input) -> (repeat (each Request).Output)? {
do {
return (repeat try (each item).evaluate(each input))
} catch {
return nil
}
}
出典: https://developer.apple.com/videos/play/wwdc2023/10168
Not documented yet
身近な例:SwiftUI
// Xcode 14.3.1 / Swift 5.8.1 まで struct ContentView: View { var body: some View { VStack { Text("1") Text("2") Text("3") Text("4") Text("5") Text("6") Text("7") Text("8") Text("9") Text("10") Text("11") } } }
// Xcode 15 / Swift 5.9 以降 struct ContentView: View { var body: some View { VStack { Text("1") Text("2") Text("3") Text("4") Text("5") Text("6") Text("7") Text("8") Text("9") Text("10") Text("11") } } }
@resultBuilder public struct ViewBuilder {
/// Builds an expression within the builder.
public static func buildExpression<Content>(_ content: Content) -> Content where Content : View
/// Builds an empty view from a block containing no statements.
public static func buildBlock() -> EmptyView
/// Passes a single view written as a child view through unmodified.
///
/// An example of a single view written as a child view is
/// `{ Text("Hello") }`.
public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1)
-> TupleView<(C0, C1)> where C0 : View, C1 : View
public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2)
-> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View
public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3)
-> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View
・・・
public static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(_ c0: C0, _ c1: C1, _ c2:
C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9)
-> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 :
View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View
}
@resultBuilder public struct ViewBuilder {
/// Builds an expression within the builder.
public static func buildExpression<Content>(_ content: Content) -> Content where Content : View
/// Builds an empty view from a block containing no statements.
public static func buildBlock() -> EmptyView
/// Passes a single view written as a child view through unmodified.
///
/// An example of a single view written as a child view is
/// `{ Text("Hello") }`.
public static func buildBlock<Content>(_ content: Content) -> Content where Content : View
public static func buildBlock<each Content>(_ content: repeat each Content)
-> TupleView<(repeat each Content)> where repeat each Content : View
}
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View ・・・ public static func buildBlock<each Content>(_ content: repeat each Content) -> TupleView<(repeat each Content)> where repeat each Content : View
public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View public static func buildBlock<C0, C1, C2, C3>(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3) -> TupleView<(C0, C1, C2, C3)> where C0 : View, C1 : View, C2 : View, C3 : View ・・・ public static func buildBlock<each Content>(_ content: repeat each Content) -> TupleView<(repeat each Content)> where repeat each Content : View
public func create<Request: JSONRPCKit.Request>(_ request: Request) -> Batch1<Request> {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
let batchElement = BatchElement(request: request, version: version, id: idGenerator.next())
semaphore.signal()
}
return Batch1(batchElement: batchElement)
public func create<Request1: Request, Request2: Request>(_ request1: Request1, _ request2: Request2) -> Batch2<Request1, Request2> {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
let batchElement1 = BatchElement(request: request1, version: version, id: idGenerator.next())
let batchElement2 = BatchElement(request: request2, version: version, id: idGenerator.next())
semaphore.signal()
}
return Batch2(batchElement1: batchElement1, batchElement2: batchElement2)
public func create<Request1: Request, Request2: Request, Request3: Request>(_ request1: Request1, _ request2: Request2, _ request3: Request3) -> Batch3<Request1, Request2, Request3> {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
let batchElement1 = BatchElement(request: request1, version: version, id: idGenerator.next())
let batchElement2 = BatchElement(request: request2, version: version, id: idGenerator.next())
let batchElement3 = BatchElement(request: request3, version: version, id: idGenerator.next())
semaphore.signal()
}
return Batch3(batchElement1: batchElement1, batchElement2: batchElement2, batchElement3: batchElement3)
public func create<Request1: Request, Request2: Request, Request3: Request, Request4: Request>(_ request1: Request1, _ request2: Request2, _ request3: Request3, _ request4: Request4) ->
Batch4<Request1, Request2, Request3, Request4> {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
let batchElement1 = BatchElement(request: request1, version: version, id: idGenerator.next())
let batchElement2 = BatchElement(request: request2, version: version, id: idGenerator.next())
let batchElement3 = BatchElement(request: request3, version: version, id: idGenerator.next())
let batchElement4 = BatchElement(request: request4, version: version, id: idGenerator.next())
semaphore.signal()
}
return Batch4(batchElement1: batchElement1, batchElement2: batchElement2, batchElement3: batchElement3, batchElement4: batchElement4)
public func create<Request1: Request, Request2: Request, Request3: Request, Request4: Request, Request5: Request>(_ request1: Request1, _ request2: Request2, _ request3: Request3, _ request4:
Request4, _ request5: Request5) -> Batch5<Request1, Request2, Request3, Request4, Request5> {
_ = semaphore.wait(timeout: DispatchTime.distantFuture)
let batchElement1 = BatchElement(request: request1, version: version, id: idGenerator.next())
let batchElement2 = BatchElement(request: request2, version: version, id: idGenerator.next())
let batchElement3 = BatchElement(request: request3, version: version, id: idGenerator.next())
let batchElement4 = BatchElement(request: request4, version: version, id: idGenerator.next())
let batchElement5 = BatchElement(request: request5, version: version, id: idGenerator.next())
semaphore.signal()
}
return Batch5(batchElement1: batchElement1, batchElement2: batchElement2, batchElement3: batchElement3, batchElement4: batchElement4, batchElement5: batchElement5)
...
出典: https://github.com/bricklife/JSONRPCKit/blob/master/Sources/JSONRPCKit/BatchFactory.swift
書き方
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<U, V, W>(_ u: U, _ v: V, _ v: W) -> (U, V, W) {
return (u, v, w)
}
func same<each T>(_ item: repeat each T) -> (repeat each T) {
return (repeat each item)
}
same(1, "a", true)
// (1, "a", true)
func same<U, V, W>(_ u: U, _ v: V, _ v: W) -> (U, V, W) {
return (u, v, w)
}
func optionalMap<each T>(_ item: repeat each T) -> (repeat Optional<each T>) {
return (repeat Optional(each item))
}
optionalMap(1, "a", true)
// (Optional(1), Optional("a"), Optional(true))
func optionalMap<each T>(_ item: repeat each T) -> (repeat Optional<each T>) {
return (repeat Optional(each item))
}
optionalMap(1, "a", true)
// (Optional(1), Optional("a"), Optional(true))
func optionalMap<each T>(_ item: repeat each T) -> (repeat Optional<each T>) {
return (repeat Optional(each item))
}
optionalMap(1, "a", true)
// (Optional(1), Optional("a"), Optional(true))
func optionalWrap<each T>(_ item: repeat each T) -> Optional<(repeat each T)> {
return Optional((repeat each item))
}
optionalWrap(1, "a", true)
// Optional((1, "a", true))
func resultMap<each T>(_ item: repeat each T) -> (repeat Result<each T, Never>) {
return (repeat Result<each T, Never>.success(each item))
}
resultMap(1, "a", true)
// (Result<Int, Never>.success(1),
// Result<String, Never>.success("a"),
// Result<Bool, Never>.success(true))
func extractResults<each T, each E: Error>(_ item: repeat Result<each T, each E>) throws
-> (repeat each T) {
return (repeat try (each item).get())
}
let r1 = Result<Int, any Error>.success(1)
let r2 = Result<String, any Error>.success("a")
let r3 = Result<Bool, any Error>.success(true)
try extractResults(r1, r2, r3)
// (1, "a", true)
func twice<each T>(_ item: repeat each T) -> (repeat each T, repeat each T) {
return (repeat each item, repeat each item)
}
twice(1, "a", true)
// (1, "a", true, 1, "a", true)
func pair<each T>(_ item: repeat each T) -> (repeat (each T, each T)) {
return (repeat (each item, each item))
}
pair(1, "a", true)
// ((1, 1), ("a", "a"), (true, true))
func append<each T, U>(_ t: (repeat each T), _ u: U) -> (repeat each T, U) {
return (repeat each t, u)
}
append((1, "a", true), 0.2)
// (1, "a", true, 0.2)
func double<each T: Numeric>(_ item: repeat each T) -> (repeat each T) {
return (repeat (each item) + (each item))
}
double(1, 0.2)
// (2, 0.4)
func double<each T: Numeric>(_ item: repeat each T) -> (repeat each T) {
return (repeat { $0 + $0 }(each item))
}
double(1, 0.2)
// (2, 0.4)
func double<each T: Numeric>(_ item: repeat each T) -> (repeat each T) {
return (
repeat { t in
t + t
}(each item)
)
}
double(1, 0.2)
// (2, 0.4)
func count<each T>(_ value: repeat each T) -> Int {
var count = 0
for _ in repeat each value {
count += 1
}
return count
}
count(1, "a", true)
// 3
protocol RequestProtocol {
associatedtype Input
associatedtype Output
}
func evaluate(_ input: Input) throws -> Output
struct Evaluator<each Request: RequestProtocol> {
var item: (repeat each Request)
}
func query(_ input: repeat (each Request).Input) -> (repeat (each Request).Output)? {
do {
return (repeat try (each item).evaluate(each input))
} catch {
return nil
}
}
出典: https://developer.apple.com/videos/play/wwdc2023/10168