
println 是底层调试函数,直接输出变量内存地址;而 fmt.Println 会调用类型的 String() 方法或按值格式化结构,才能正确显示 jwt.MapClaims 中的 "username" 等字段。
`println` 是底层调试函数,直接输出变量内存地址;而 `fmt.println` 会调用类型的 `string()` 方法或按值格式化结构,才能正确显示 `jwt.mapclaims` 中的 `"username"` 等字段。
在 Go 中,println 并非为常规开发设计的打印函数——它是运行时内置的低级调试工具,不执行类型格式化,对复合类型(如 map[string]interface{}、jwt.MapClaims)仅输出其底层指针地址(例如 (0x2b3c20,0xc420075420)),而非内容。这正是你看到“两个内存地址”而非 "adam" 的根本原因。
而 fmt.Println(及整个 fmt 包)基于反射和接口实现智能格式化:当传入 jwt.MapClaims(本质是 map[string]interface{})时,它会递归遍历键值对,调用各值的 String() 方法(若实现)或按默认规则转为字符串,最终输出可读结果,例如:
res := getToken() fmt.Println(res["username"]) // 输出: adam fmt.Println(res) // 输出: map[username:adam password:test iat:1.487206692e+09 exp:1.518764292e+09]
✅ 正确做法:始终使用 fmt 包进行开发期输出
❌ 避免使用 println(除非极简启动调试,且明确知晓其行为限制)
此外,注意 jwt.MapClaims 是一个类型别名:
type MapClaims map[string]interface{}
它本身未实现 String() 方法,但 fmt 能自动处理 map 类型的结构化打印,无需额外改造函数签名(如返回 *jwt.MapClaims 或手动解引用)。你的原始 getToken() jwt.MapClaims 定义完全合理,问题仅在于输出方式。
? 小贴士:
- 在
main或测试中,优先导入"fmt"并使用fmt.Printf("%+v", res)查看完整结构(%+v显示字段名,对嵌套结构更友好); - 若需日志记录,推荐
log.Printf或结构化日志库(如zap),而非println; -
println在 Go 标准文档中明确标注为 “for debugging only”,生产代码中应完全避免。
总结:不是指针或解引用的问题,而是输出机制的选择错误。切换到 fmt.Println,一切自然清晰。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











