Swift Digest
Blog | Swift.org Blog

Swift 6.1 リリース

Swift 6.1 Released

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

主な変更点

言語と標準ライブラリ

並行処理: 型・エクステンションへの nonisolated

Swift の並行処理モデルでは、プロパティや関数に nonisolated を書くことで、その API が任意の並行コンテキストから安全に呼び出せることを示せます。Swift 6.1 では nonisolated を型やエクステンションにも書けるようになりました。これにより、型への @MainActor 推論を防いだり、エクステンション内のすべてのメソッドに個別の注釈なしで nonisolated を適用したりできます。

@MainActor
struct S {
  let id: Int
  let name: String

  // ミュータブルな状態と MainActor のメソッド
}

nonisolated extension S: CustomStringConvertible, Equatable {
  var description: String {
    "id: \(id), name: \(name)"
  }

  static func ==(lhs: S, rhs: S) -> Bool {
    lhs.id == rhs.id
  }
}

詳しくは SE-0449 のダイジェストを参照してください。

並行処理: task group の結果型推論

Swift 6.1 では withTaskGroupwithThrowingTaskGroup の子タスク結果型が推論されるようになりました。従来は task group を作成する際に、子タスクの結果型を引数として必ず書く必要がありました。

let messages = await withTaskGroup(of: Message.self) { group in
  for id in ids {
    group.addTask { await downloadMessage(for: id) }
  }

  var messages: [Message] = []
  for await message in group {
    messages.append(message)
  }
  return messages
}

Swift 6.1 では、子タスクの結果型を task group のクロージャから推論できます。

// 以前のような (of: Message.self) は不要
let messages = await withTaskGroup { group in
  for id in ids {
    group.addTask { await downloadMessage(for: id) }
  }

  var messages: [Message] = []
  for await message in group {
    messages.append(message)
  }
  return messages
}

データ競合安全性の親しみやすさは引き続き活発に開発が進んでいる領域です。方針の全体像はデータ競合安全性の親しみやすさを高めるための vision ドキュメントにまとめられており、関連する多くの Swift Evolution Proposal がレビュー中です。

Objective-C の型を Swift で実装する

Swift 6.1 では新しい属性 @implementation が加わりました。@objc と組み合わせて、Objective-C からインポートした宣言に対する実装を提供するために使えます。Swift の extension@objc @implementation を書くと、Objective-C の @implementation ブロックを置き換えられます。

ヘッダは通常どおり Objective-C のクラスとして書きますが、実装は Objective-C ファイルの @implementation ではなく、Swift ファイルの @objc @implementation extension として書きます。既存クラスの実装を、後方互換性を壊さずにカテゴリ単位で少しずつ Swift へ移植することもできます。詳しくは SE-0436 のダイジェストを参照してください。

生産性の向上: 末尾カンマの拡大

Swift では、コレクションリテラルに末尾カンマを書くことで、最後の要素もほかの要素と同じように追加・削除・並べ替え・コメントアウトしやすくなっています。

let rank = [
  "Player 1",
  "Player 3",
  "Player 2",
]

Swift 6.1 では、末尾カンマをタプル、パラメータリストと引数リスト、ジェネリックパラメータリスト、クロージャのキャプチャリスト、文字列補間にも書けるように拡張されました。

let numbers = [1, 2, 0, 3, 4, 0, 0, 5]

let subsequences = numbers.split(
    separator: 0,
    maxSplits: 1,
)

開発の手触りが良くなるだけでなく、プラグインやマクロのようなコード生成ツールも単純化できます。カンマ区切りのリストを生成する際に、最後の要素だけを特別扱いする条件分岐が不要になるためです。詳しくは SE-0439 のダイジェストを参照してください。

パッケージとビルドの改善

Swift 6.1 では package traits が導入されました。これは、Embedded Swift や WebAssembly といった特定の環境で使われるときに、異なる API・機能を提供できる新しいパッケージ設定です。パッケージの作者は Package.swift で自分のパッケージが提供する trait の集合を定義でき、条件付きコンパイルやオプションの依存関係を表現できます。パッケージはデフォルトで有効になる trait を指定でき、利用側は依存関係を宣言する際に使う trait をカスタマイズできます。

dependencies: [
  .package(
    url: "https://github.com/Org/SomePackage.git",
    from: "1.0.0",
    traits: [
      .default, // パッケージのデフォルト trait をすべて有効にする
      "Embedded"
    ]
  ),
]

詳しくは SE-0450 のダイジェストを参照してください。

ジャンプ先の定義表示など、多くの編集機能はインデックスによって支えられています。Swift 6.1 より前は、インデックスはプロジェクトのビルド時に行われていたため、ライブラリへの追加・変更がこれらの編集機能に反映されるのはビルド後でした。Swift 6.1 では、SourceKit-LSP の SwiftPM プロジェクトに対して background indexing がデフォルトで有効になり、プロジェクトを変更するたびにモジュール横断・グローバルな機能が最新に保たれます。

Swift Testing

Swift 6.1 では、テストの実行前後にロジックを差し込んで、セットアップ・後始末の処理を共有できるカスタム trait が使えるようになりました。新しい TestScoping プロトコルに適合するカスタム trait 型を書くと、その trait が適用された各テストやスイートの実行スコープをカスタマイズするメソッドを実装できます。たとえば、task local な値をモックのリソースに束縛する trait を実装できます。

struct MockAPICredentialsTrait: TestTrait, TestScoping {
  func provideScope(for test: Test, testCase: Test.Case?, performing function: @Sendable () async throws -> Void) async throws {
    let mockCredentials = APICredentials(apiKey: "fake")
    try await APICredentials.$current.withValue(mockCredentials) {
      try await function()
    }
  }
}

extension Trait where Self == MockAPICredentialsTrait {
  static var mockAPICredentials: Self { Self() }
}

@Test(.mockAPICredentials)
func example() {
  // APICredentials.current を参照しつつ API の利用を検証する...
}

詳しくは ST-0007 のダイジェストを参照してください。また Swift 6.1 の Swift Testing には、捕捉したエラーを返すように改良された #expect(throws:)#require(throws:) マクロも含まれます。テスト関数内でエラーを検査しやすくなりました(ST-0006)。

Swift-DocC

Swift-DocC には、パラメータ型と戻り値型の情報に基づく、より人間にとって読み書きしやすいシンボルリンクの曖昧性解消の方法が加わりました。たとえば、パラメータ型と戻り値型が異なる次の 3 つのオーバーロードを考えます。

func doSomething(first: String,  second: Int) -> Double
func doSomething(first: String?, second: Int) -> Float
func doSomething(first: String?, second: Int) -> Double

従来は、これらのオーバーロードへのリンクを書く際、特定のオーバーロードを一意に参照するために、シンボルの一意な識別子の短いハッシュ(-3c5j など)を含める必要がありました。このハッシュからどのオーバーロードを指すのかを人間が読み取ることはできません。Swift 6.1 では、-(String,_)->Float-(String?,_)->Double のように、パラメータ型と戻り値型の組み合わせを使ってリンクの曖昧性を解消し、特定のオーバーロードを一意に参照できます。

各オーバーロードを区別する最小限のパラメータ型・戻り値型の組み合わせは、曖昧なシンボルリンクに関する Swift-DocC の警告から知ることができます。

Swift 利用者への影響

関連 Proposal・リンク