golang for循环取值为啥不按顺序输出?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang for循环取值为啥不按顺序输出?相关的知识,希望对你有一定的参考价值。

package main

import (
"fmt"
)

func main()
data :=map[int]int0: 0, 1: 1, 2: 2, 3: 3
for k,v := range data
fmt.Println(k,"->",v)



输出:
3 -> 3
0 -> 0
1 -> 1
2 -> 2

Go 语言中的 for 循环不会按照顺序输出,因为它不是一个有序的过程。for 循环采用的是“基于条件的循环”,而不是“基于步长的循环”。这意味着当条件满足时,for 循环会执行一次,而不是每次都按照指定的步长执行一次。 参考技术A map底层用的hashmap数据结构,没法保证编码时加入的顺序,也没法保证key的顺序,所以在range访问时,它也会随机一个起点。官方有解释。 参考技术B map是无序的。

为啥 Swiftui 中主线程不按顺序排列

【中文标题】为啥 Swiftui 中主线程不按顺序排列【英文标题】:Why the main thread is not in sequence in Swiftui为什么 Swiftui 中主线程不按顺序排列 【发布时间】:2020-09-20 01:23:30 【问题描述】:

我在 SwiftUI 中有以下功能。 JSON 正在解析正确的数据,但顺序是:P1、P2、P5、P6、P3 和 P4。我需要 P1、P2、P3、P4、P5 和 P6。有人可以帮我吗?我不明白为什么不遵循逻辑线程。

    
struct ContentView: View 
    
    var body: some View 
        
        Button ("Action", action:  self.checkLogin(username:"test", password:"123456")  )
 

func checkLogin (username: String, password: String) 
    var body: [String:String] = [:]
    guard let url = URL(string: "http://test/apple/login.php") else  return  
    body = ["user": username, "password": password]
    let finalBody = try! JSONEncoder().encode (body)
    print("final",body)
    var request = URLRequest(url: url)
    print("p1")
    request.httpMethod = "POST"
    request.httpBody = finalBody
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    print("p2")

    let task = URLSession.shared.dataTask(with: request)  (data,response,error) in
        print("p3")
        if let error = error  print ("Error: \(error)")
                               return
           
        guard let data = data else  return 
        do 
            print("p4")
            let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
            print (finalData)
           
    
    print ("p5")
        task.resume()
    print ("p6")
        return


struct ServerMessage: Decodable 
    let result: String
    let nuser: String

【问题讨论】:

在某处了解异步流(编程)概念,例如。 medium.com/ios-os-x-development/…. 【参考方案1】:

您创建的 URLSession 有一个名为 dataTask 的函数,它在后台线程上执行:

let task = URLSession.shared.dataTask(with: request)  (data,response,error) in
        print("p3")
        if let error = error  print ("Error: \(error)")
                               return
           
        guard let data = data else  return 
        do 
            print("p4")
            let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
            print (finalData)
           
    

在调用task.resume()之前它不会被执行,这就是原因

print("p5")

首先被调用,并将在您的控制台上注册日志。

当 task.resume() 被调用时,它会在另一个线程中执行,从而使执行与主线程异步。这意味着主线程将立即执行

print ("p6")

后台线程大约在同一时间执行“任务”:执行请求并等待响应。一旦有响应,就会执行:

print("p3")

如果请求没有错误,

print("p4")

将执行,如果响应的数据有错误,您将不会在控制台上看到“p4”打印出来,因为您对此有所防范。

为保证您获得所需的订单结果,您必须将打印调用放在该 API 的完成处理程序中

 let task = URLSession.shared.dataTask(with: request)  (data,response,error) in
        print("p3")
     
        if let error = error  
              print ("Error: \(error)")
              return
        

        guard let data = data else  return 
        
        do   
            let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
            print (finalData)
            // Here is where you put non-UI code after you get a successful            
            // response and will guarantee that you get your data first
            print("p4")


           // Also keep in mind that since this is a background thread,           
           // you need to call the main thread in order to make your UI changes 
            DispatchQueue.main.async 
                  // All your UI changes here, so they will run on the main thread
                  print("p5")
                  print("p6")
            
         
         catch 
                 print("Error parsing data")
         
    
    task.resume() 
    return

Apple 已弃用您之前可以使用 NSURLConnection 执行的同步请求 API,请参见此处:https://developer.apple.com/documentation/foundation/nsurlconnection/1411393-sendsynchronousrequest?language=objc

这是因为用户不会喜欢无响应的应用。让网络调用阻塞主线程就可以做到这一点。

您可以在此处阅读更多关于闭包的信息https://docs.swift.org/swift-book/LanguageGuide/Closures.html

【讨论】:

@EduardoMartinez 您不需要在主线程上运行任务,也不需要 P1-P6 的顺序。您需要了解异步数据处理的工作原理。 经过一番挖掘,我发现苹果不推荐使用同步请求是有原因的,见这里:developer.apple.com/documentation/foundation/nsurlconnection/… 我已更新我的答案以反映这一点。希望这会有所帮助,祝你好运! 非常感谢乔安娜。我是 swiftui 的新手。对于日志屏幕,我需要一个函数来验证用户是否已注册。我该怎么做?我需要服务器回答才能给予访问权。请问有什么线索吗? 嘿@EduardoMartinez,我已经修改了我的答案,以说明最好将代码放在哪里以达到您想要的顺序。希望这会有所帮助!

以上是关于golang for循环取值为啥不按顺序输出?的主要内容,如果未能解决你的问题,请参考以下文章

为啥正常的 for 循环允许为结构字段分配值,而 for range 在 Golang 中不起作用? [复制]

关于java中HasMap的遍历输出不按顺序

关于java中HasMap的遍历输出不按顺序

为啥 Swiftui 中主线程不按顺序排列

“for (... in ...)”循环中的元素顺序

“for (... in ...)”循环中的元素顺序