# Swift 5.8の新機能 ## 参考ページ Swift 5.8 Released! https://www.swift.org/blog/swift-5.8-released/ ## 1. SE-0362: Piecemeal adoption of upcoming language improvements swift 6で有効になる機能などを先行的に試せるようになった。 使い方は `-enable-upcoming-feature XXX` をOther Swift Flagに入れる(Xcode Projの場合) 例として以下の4つが挙げられていた - SE-0274: Concise magic file names (ConciseMagicFile) - SE-0286: Forward-scan matching for trailing closures (ForwardTrailingClosures) - SE-0335: Introduce existential any (ExistentialAny) - SE-0354: Regex literals (BareSlashRegexLiterals) ### SE-0274: Concise magic file names https://github.com/apple/swift-evolution/blob/main/proposals/0274-magic-file.md #fileの出力が変わるやつ。 ||swift 5.8 通常|-enable-upcoming-feature ConciseMagicFile| |---|---|---| |#file|/Users/UserName/XcodeProjeRoot/Module/ContentView.swift|ModuleName/ContentView.swift| |#filePath|/Users/UserName/XcodeProjeRoot/Module/ContentView.swift|/Users/UserName/XcodeProjeRoot/Module/ContentView.swift| `fatalError("Something bad happened!")` などの時も `Fatal error: Something bad happened!: file Module/ContentView.swift, line 3` と #fileを見ているので影響があるらしい Pathは開発者毎に違うので便利そう。有効にしてもいいかも ### SE-0286: Forward-scan matching for trailing closures https://github.com/apple/swift-evolution/blob/main/proposals/0286-forward-scan-trailing-closures.md trailing closuresのスキャンが前方からになる変更 multiple trailing closuresの関係で色々壊れていたのを修正するらしい 具体的には現状 ```swift= func animate( withDuration duration: TimeInterval, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil ) ``` こういうfuncに対して ```swift= UIView.animate(withDuration: 0.3) { self.view.alpha = 0 } ``` これが書けないのが問題でそれを修正できるらしい。(completionはdefault = nilでtrailing closureはanimationsになってほしいがそれができてない) 逆に前方からになることで壊れることとかないのかなって思ったりするけど詳しいことは理解できなかった。 iOS Xcode Projではもう有効っぽい ### SE-0335: Introduce existential any (ExistentialAny) https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md Twitterとかでも話題のやつ 存在型をletなどで宣言する際にanyを強制する。 具体的には ```swift= protocol CacheDataStore { ... } struct CacheDataStoreImpl: CacheDataStore { ... } struct HogeRepository { let cacheDataStore: CacheDataStore init(cacheDataStore: CacheDataStore) { self.cacheDataStore = cacheDataStore } } let hogeRepository = HogeRepository(cacheDataStore: CacheDataStoreImpl()) ``` というコードがコンパイルエラーになり ```swift= protocol CacheDataStore { ... } struct CacheDataStoreImpl: CacheDataStore { ... } struct HogeRepository { let cacheDataStore: any CacheDataStore init(cacheDataStore: any CacheDataStore) { self.cacheDataStore = cacheDataStore } } let hogeRepository = HogeRepository(cacheDataStore: CacheDataStoreImpl()) ``` という感じになる。 この記事が詳しく書かれている https://zenn.dev/treastrain/articles/555d4a2fc1b40b 上の記事からの参照ですがこのFix All Issuesすごい役に立った ![](https://hackmd.io/_uploads/S1hKbpWB2.png) またAuto Fixは完全ではないため以下のことに気をつける必要がある |before|AutoFix|正しい書き方| |----|----|----| |cacheDataStore: CacheDataStore?|cacheDataStore: any CacheDataStore?|cacheDataStore: (any CacheDataStore)?| |cacheDataStore: CacheDataStore!|cacheDataStore: any CacheDataStore!|cacheDataStore: (any CacheDataStore)!| ### SE-0354: Regex literals (BareSlashRegexLiterals) https://github.com/apple/swift-evolution/blob/main/proposals/0354-regex-literals.md Regexを `/(?<identifier>[[:alpha:]]\w*) = (?<hex>[0-9A-F]+)/` こんな感じでかけるようにするもの iOSのXcode Projectでは現在ももう書けるのでSwift Package Managerで作ったSwift Serverとかでの話だと思われる(なんでiOSのXcode Projectはかけるようになっているかは不明) ## SE-0365 Allow implicit self for weak self captures, after self is unwrapped `[weak self]` を `guarad let self` 以降はselfなしで書けるようになる ```swift= class ViewController { let button: Button func setup() { button.tapHandler = { [weak self] in guard let self else { return } dismiss() } } func dismiss() { ... } } ``` `guarad let self = self` でもいけた ## SE-0367 Conditional compilation for attributes attributesに対してConditional compilationを書けるようになった 具体的にはこんな感じ ```swift= #if hasAttribute(preconcurrency) @preconcurrency #endif protocol P: Sendable { func f() func g() } ``` ちなみに `@preconcurrency` はswift 5.6で導入されている https://github.com/apple/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md @Sendableに対応しなきゃだけで今はできないからみたいな時につけておくとコンパイラーが許してくれるやつっぽいのでこれも今後使いそうなので見ておきたい ## SE-0373: Lift all limitations on variables in result builders https://github.com/apple/swift-evolution/blob/main/proposals/0373-vars-without-limits-in-result-builders.md ResultBuilderの中で色々な制限が解除された模様 こういうlazyや > https://www.hackingwithswift.com/swift/5.8/lift-result-builder-limitations ```swift= import SwiftUI struct ContentView: View { var body: some View { VStack { lazy var user = fetchUsername() Text("Hello, \(user).") } .padding() } func fetchUsername() -> String { "@twostraws" } } ``` Property Wrapperが使えるようになったらしい ```swift= import SwiftUI struct AppIntroView: View { var body: some View { @UserDefault(key: "user_has_ever_interacted") var hasInteracted: Bool ... Button("Browse Features") { ... hasInteracted = true } Button("Create Account") { ... hasInteracted = true } } } ``` 具体的これいいなって思ったのはないので使わないかも。。。 ## SE-0376: Function Back Deployment https://github.com/apple/swift-evolution/blob/main/proposals/0376-function-back-deployment.md バックデプロイ用の何か この記事 > https://www.hackingwithswift.com/swift/5.8/function-back-deployment によるとこんなのが書けるようになるらしい ```swift= extension Text { @backDeployed(before: iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0) @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *) public func monospaced(_ isActive: Bool) -> Text { fatalError("Implementation here") } } ``` すごいいいじゃんって思ったけど手元で試した限りはうまく動かずiOS 16でもkoこのextensionのmonospacedが呼ばれてしまっていてよくわからなかった。 ライブラリ側で使える機能なのかもしれない。。。