range迭代map是有序的吗?

在Go语言中,range 关键字用于迭代 map(映射)时,遍历顺序是不确定的。Go标准库并没有明确规定 map 的遍历顺序,因此不应该依赖于 map 的遍历顺序。每次程序运行时,map 的遍历顺序可能会有所不同,即便对于同样的键值对集合,也无法保证前后两次遍历的顺序相同。

如果你想按一定的顺序遍历 map,可以先将 map 的 key 转换为一个切片(slice),然后对这个切片进行排序,再通过排序后的 key 列表依次访问 map 中的元素。例如:

m := map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

// 获取 map 的 key 切片
keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

// 对 key 切片进行排序
sort.Ints(keys)

// 按照排序后的 key 遍历 map
for _, k := range keys {
    v := m[k]
    fmt.Println(k, v)
}

这样可以确保每次遍历 map 都是按照 key 的升序顺序进行的。

场景: 制作登录系统, 允许手机端, pc端, 平板端多端登录, 一旦有一端修改密码, 其它端登陆态失效, 如何设计?

要实现多端登录且修改密码后其它端登录态失效的系统,可以采取以下设计方案:

  1. 令牌(Token)机制

    • 使用JWT(JSON Web Tokens)或者自定义的令牌机制,客户端登录成功后,服务器颁发一个有效期的令牌给客户端。
    • 令牌中可以包含用户标识和过期时间等信息,客户端每次请求时都需要携带该令牌。
    • 服务器端验证令牌有效性和用户状态,如果令牌无效或用户状态(如密码已修改)发生变化,服务器拒绝请求并返回错误信息。
  2. 登出和令牌撤销

    • 设计一个服务端的令牌撤销列表(黑名单)或者令牌刷新机制。
    • 当某一端修改密码时,除了更新密码之外,将所有已发放的该用户的令牌加入到撤销列表或标记为无效。
    • 客户端在下次请求时,由于令牌已经失效,会被要求重新登录。
  3. 长连接或心跳机制

    • 对于实时性要求高的场景,可以借助WebSocket或Socket.io等实现实时通讯,当用户密码修改时,服务器可以即时通知到已登录的客户端,令其登出。
  4. 服务端事件驱动

    • 使用事件驱动架构,当密码修改事件发生时,触发一个事件处理器,该处理器负责清理所有旧的登录凭证或通知相关服务撤销登录令牌。
  5. 数据库设计

    • 用户表中记录最后一次修改密码的时间戳或版本号,令牌中包含版本信息,当密码修改时更新版本号,服务器在验证令牌时检查版本是否一致。
  6. OAuth2 Refresh Token

    • 在OAuth2中,可以使用Refresh Token机制。当密码修改时,所有的Access Token都将失效,即使客户端持有Refresh Token也不能用来获取新的Access Token,直到用户重新登录。

实现流程示例:

  • 用户在任一端修改密码后,服务器端在更新密码的同时,更新用户的相关状态,撤销所有旧的登录令牌。
  • 已登录的客户端在下一次发送请求时,由于令牌失效,服务器返回登录失效信息。
  • 客户端收到登录失效信息后,引导用户重新登录。

总体而言,关键是确保服务器端能够实时感知并处理密码变更事件,并及时通知各端撤销原有的登录凭据。

最后编辑: kuteng  文档更新时间: 2024-04-02 09:53   作者:kuteng