有个 go 的问题,求解答

2020-06-12 10:28:33 +08:00
 lancelock

最近尝试用 gin 写一个个人项目,有个问题就是,因为 golang 里用大小写控制访问权限,所以我定义的 struct 的属性名都是大写的,这样以 json 格式返回后 key 也都是首字母大写的 PascalCase 风格,但我需要 cameCase 风格,有什么办法统一处理吗?

我目前知道可以在定义 struct 的时候加json的 tag,但是一个有点麻烦,另一个就是对于一些第三方依赖包里定义的 struct 就没有办法了,有什么优雅的办法吗?

4582 次点击
所在节点    Go 编程语言
31 条回复
Hanggi
2020-06-12 12:50:49 +08:00
@lancelock 我说得很清楚了,Go 是静态语言,不要想着什么 marshal 之类的优雅解决。
你要做的就是定义一个 response 结构体,把你要返回的数据 mapping 上去。
你可以用一些工具简化这个操作,但是结果都是一样的。

如果你觉得麻烦,不想这样,可以考虑使用 Nodejs 这种动态语言。
lancelock
2020-06-12 13:28:20 +08:00
@Hanggi 我返回的数据就是个结构体你听不听得懂人话?求你别回我了
blessyou
2020-06-12 13:29:57 +08:00
那看起来还是转换风格比较 easy 。
sunxiansong
2020-06-12 13:58:26 +08:00
VSCode go 插件有个命令:Go: Add Tags To Struct Fields

不过缺点是支持 snake_case,不知道在哪里改

好在我找到 VSCode 有个插件 change-case ,可以方便的在不认风格间切换
yxlimo
2020-06-12 14:03:50 +08:00
我觉得问题的点在于,你为什么要依赖第三方包的 struct 生成 response 。这样子是不可控的
Hanggi
2020-06-12 14:15:34 +08:00
@lancelock 怪心累的,听不懂人话呢,只说最后一次。

看你问这个问题就知道你没怎么用过 go 语言。你以为你是这世界上第一个有这种需求的人吗?
go 语言发展了 10 年为什么找不到你要的所谓的第三方依赖包,因为 go 语言不提倡这么做。

像 #13 楼说的 reflect 其实就是一种动态判断类型的方法,但是,不要这么做,原因自己查。

不要什么后置中间件统一处理,如果你非要这么做可能 go 语言不适合你。


go 语言 json struct 可以嵌套你知道吧?你要做的就是定义好结构体,加好 tag,组合使用他们。
如果这样还看不懂,你也不用回了。
labulaka521
2020-06-12 14:34:32 +08:00
定义 tag ?
iceiceice
2020-06-12 15:21:40 +08:00
package jsonconv

import (
"bytes"
"encoding/json"
"log"
"regexp"
"strconv"
"strings"
"unicode"
)

/*************************************** 下划线 json ***************************************/
type JsonSnakeCase struct {
Value interface{}
}

func (c JsonSnakeCase) MarshalJSON() ([]byte, error) {
// Regexp definitions
var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
var wordBarrierRegex = regexp.MustCompile(`(\w)([A-Z])`)
marshalled, err := json.Marshal(c.Value)
converted := keyMatchRegex.ReplaceAllFunc(
marshalled,
func(match []byte) []byte {
return bytes.ToLower(wordBarrierRegex.ReplaceAll(
match,
[]byte(`${1}_${2}`),
))
},
)
return converted, err
}

/*************************************** 驼峰 json ***************************************/
type JsonCamelCase struct {
Value interface{}
}

func (c JsonCamelCase) MarshalJSON() ([]byte, error) {
var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
marshalled, err := json.Marshal(c.Value)
converted := keyMatchRegex.ReplaceAllFunc(
marshalled,
func(match []byte) []byte {
matchStr := string(match)
key := matchStr[1 : len(matchStr)-2]
resKey := Lcfirst(Case2Camel(key))
return []byte(`"` + resKey + `":`)
},
)
return converted, err
}

/*************************************** 其他方法 ***************************************/
// 驼峰式写法转为下划线写法
func Camel2Case(name string) string {
buffer := NewBuffer()
for i, r := range name {
if unicode.IsUpper(r) {
if i != 0 {
buffer.Append('_')
}
buffer.Append(unicode.ToLower(r))
} else {
buffer.Append(r)
}
}
return buffer.String()
}

// 下划线写法转为驼峰写法
func Case2Camel(name string) string {
name = strings.Replace(name, "_", " ", -1)
name = strings.Title(name)
return strings.Replace(name, " ", "", -1)
}

// 首字母大写
func Ucfirst(str string) string {
for i, v := range str {
return string(unicode.ToUpper(v)) + str[i+1:]
}
return ""
}

// 首字母小写
func Lcfirst(str string) string {
for i, v := range str {
return string(unicode.ToLower(v)) + str[i+1:]
}
return ""
}

// 内嵌 bytes.Buffer,支持连写
type Buffer struct {
*bytes.Buffer
}

func NewBuffer() *Buffer {
return &Buffer{Buffer: new(bytes.Buffer)}
}

func (b *Buffer) Append(i interface{}) *Buffer {
switch val := i.(type) {
case int:
b.append(strconv.Itoa(val))
case int64:
b.append(strconv.FormatInt(val, 10))
case uint:
b.append(strconv.FormatUint(uint64(val), 10))
case uint64:
b.append(strconv.FormatUint(val, 10))
case string:
b.append(val)
case []byte:
b.Write(val)
case rune:
b.WriteRune(val)
}
return b
}

func (b *Buffer) append(s string) *Buffer {
defer func() {
if err := recover(); err != nil {
log.Println("*****内存不够了!******")
}
}()
b.WriteString(s)
return b
}

func TestJsonCamelCase_MarshalJSON(t *testing.T) {
type Person struct {
HelloWold string
LightWeightBaby string
}
var a = Person{HelloWold: "xxx", LightWeightBaby: "muscle"}
res, _ := json.Marshal(JsonCamelCase{a})
fmt.Printf("%s", res)
}
BlackBerry999
2020-06-12 16:35:55 +08:00
@iceiceice 秀!
lancelock
2020-06-12 17:38:45 +08:00
@iceiceice 可以,给力
zoharSoul
2020-12-18 17:57:31 +08:00
@Hanggi 你这啥理解能力?
别人已经说得很清楚了, 它定义了 struct.
而且这和静态 /动态语言有啥关系.
java 是不是静态? 一样可以指定序列号模式.

一知半解在这指点江山

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/680907

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX