Go 语言中类型不匹配导致的逻辑失效

six73764 发布于 2026-01-10 22 次阅读


今天在开发中,遇到了一个问题,由于出现了bug,我需要暂时关闭我应用中的业务锁功能,即让用户无法打开。这个逻辑非常简单,用户的应用锁设置存在 user_setting 表中,1 为开启,0 为关闭。当用户需要开启或关闭用户锁时,需要 put /user/setting这个接口,然后在请求的 body 中以 JSON 格式带上device_lock=1/0,即可开启/关闭设备锁,于是我使用如下代码来拦截用户开启设备锁的操作

func (u *User) userUpdateSetting(c *gin.Context) {
	// 获取用户uid
	loginUIDAny, exists := c.Get("login_uid")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{
			"error": "未登录",
		})
		return
	}
	loginUID := loginUIDAny
        // 获取body
	var reqMap map[string]interface{}
	if err := c.BindJSON(&reqMap); err != nil {
		u.Error("数据格式有误!", zap.Error(err))
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "数据格式有误!",
		})
		return
	}

	// 查询用户信息
	users, err := u.db.QueryByUID(loginUID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": "查询用户信息出错!",
		})
		return
	}
	if users == nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "用户信息不存在!",
		})
		return
	}

	for key, value := range reqMap {
		if key == "device_lock" ||
			key == "search_by_phone" ||
			key == "search_by_short" ||
			key == "new_msg_notice" ||
			key == "msg_show_detail" ||
			key == "offline_protection" ||
			key == "voice_on" ||
			key == "shock_on" ||
			key == "mute_of_app" {
			// 新增特殊判断
			if key == "device_lock" && value == 1 {
				c.JSON(http.StatusBadRequest, gin.H{
					"error": "设备锁功能未启用",
				})
				return
			}

			err = u.db.UpdateUsersWithField(
				key,
				fmt.Sprintf("%v", value),
				loginUID,
			)
			if err != nil {
				u.Error("修改用户资料失败", zap.Error(err))
				c.JSON(http.StatusInternalServerError, gin.H{
					"error": "修改用户资料失败",
				})
				return
			}
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "success",
	})
}

我简单的加了一个 if key == "device_lock" && value == 1来拦截用户的开启操作,但是我测试却发现这个 if 始终无法生效,于是我直接求助万能的ChatGPT。

究其原因在于,我使用了 var reqMap map[string]interface{}来定义接收的JSON,并使用Gin框架的BindJSON方法来解析请求参数,在 Go 中,使用 encoding/json(或兼容的库)将 JSON 数据解析到 map[string]interface{} 时,所有的数字默认会被解析为 float64 类型。当客户端送 {"device_lock": 1} 时,键device_lock对应的键值 1 其实是float64类型的,值为 1.0,而 if 中的value == 1 这里的 1 是一个无类型常量(untyped int),并且由于理论上在Go中写诸如float64(1) == int(1)这种不同类型的逻辑运算是无法通过编译的,而在这个地方,Go 的规则是:当比较interface{} == untyped int时编译器会把无类型常量自动转换成 interface{}。也就是说,编译器实际看到的是:

interface{}(float64(1)) == interface{}(int(1))

而这在Go中,不会报错,只会的恒等于 false ,所以才导致了我的 if 无法正确拦截。

最后将这个 if 改为:

if key == "device_lock" && fmt.Sprintf("%v", value) == "1"

运行就正常了。

此作者没有提供个人介绍。
最后更新于 2026-01-10