简体   繁体   中英

Swift 5.5 async let - error: expression is 'async' but is not marked with 'await'

WWDC21 introduces Swift 5.5 , with async/await . Following the Explore structured concurrency in Swift and Meet async/await in Swift WWDC21 sessions, I'm trying to use the async let function.

Here's my Playground code:

func doIt() async -> String {
    let t = TimeInterval.random(in: 0.25 ... 2.0)
    Thread.sleep(forTimeInterval: t)
    return String("\(Double.random(in: 0...1000))")
}

async {
    async let a = doIt()
    async let b = doIt()
    async let c = doIt()
    async let d = doIt()
    
    let results = await [a, b, c, d]
    for result in results {
        print("  \(result)")
    }
}

However, for each of the "async let" lines, I get this error:

error: AsyncLetSwift55WWDC21.playground:12:15: error: expression is 'async' but is not marked with 'await'
    async let a = doIt()
              ^
              await 

Paul Hudson's blog showed this example: 使用 Swift 异步进行黑客攻击示例

The Exploring structured currency video has this example at about the 8:10 mark: 在此处输入图像描述

EDIT: This does seem to be a Playground-specific issue. Per the suggestion on the same issue in Apple Developer Forums , running the same code ( ok, I did add sleep(10) to the end of the source file after the async block for macOS, so the app wouldn't terminate before the async calls completed ) as a macOS command-line project gives no errors and produces the proper output.

Is this a bug, or am I just not understanding something?

My advice would be: don't try this in a playground. Playgrounds aren't ready for this stuff yet. Your code compiles and runs fine in a real project. Here's an example:

class ViewController: UIViewController {
    
    func doIt() async -> String {
        let t = TimeInterval.random(in: 0.25 ... 2.0)
        Thread.sleep(forTimeInterval: t)
        return String("\(Double.random(in: 0...1000))")
    }
    func test() {
        async {
            async let a = doIt()
            async let b = doIt()
            async let c = doIt()
            async let d = doIt()
            
            let results = await [a, b, c, d]
            for result in results {
                print("  \(result)")
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        test()
    }
}

Building as a macOS command line project (Xcode: File -> New -> Project, then select "Command Line Tool" from the macOS tab), the code works perfectly. (This was a suggestion from a response in the Apple Developer Forums .)

I've added a single sleep(10) to the end so that the command line tool doesn't exit before the async calls finish:

import Foundation

print("Hello, world!")

func doIt() async -> String {
    let t = TimeInterval.random(in: 0.25 ... 2.0)
    Thread.sleep(forTimeInterval: t)
    return String("\(Double.random(in: 0...1000))")
}

async {
    async let a = doIt()
    async let b = doIt()
    async let c = doIt()
    async let d = doIt()
    
    let results = await [a, b, c, d]
    for result in results {
        print("  \(result)")
    }
}
sleep(10)

This produces the expected sort of console output (Note: the actual values will differ on every run)*:

Hello, World!
  415.407747869283
  574.28639828183
  689.4706625185836
  385.56539085197113
Program ended with exit code: 0

It runs well as macOS command line project, but when I created it as a iOS project,

Those codes:

async let a = doIt()
async let b = doIt()
async let c = doIt()
async let d = doIt()

DO NOT runs in parallel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM