要解析的 json, 格式不完美. 比如
[{ "name": "Abyssin", "price": 500, "location": "Lviv", "image": "https://olxua-ring02.akamaized.net/images_slandocomua/476948786_2_1000x700_abissenysh-chempion-fotografii.jpg" }, { "name": "Abyssin", "price": "550", "location": "Lviv", "image": "https://olxua-ring10.akamaized.net/images_slandocomua/342850976_3_1000x700_abidetki-koti_rev006.jpg" }]
price 实际上是个 int 但是有些值是 string. 加 tag 就没啥用了, 只能自己写 UnmarshalJSON
好奇看了一下
json/decode
// indirect walks down v allocating pointers as needed, // until it gets to a non-pointer. // If it encounters an Unmarshaler, indirect stops and returns that. // If decodingNull is true, indirect stops at the first settable pointer so it // can be set to nil. func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { // Issue #24153 indicates that it is generally not a guaranteed property // that you may round-trip a reflect.Value by calling Value.Addr().Elem() // and expect the value to still be settable for values derived from // unexported embedded struct fields. // // The logic below effectively does this when it first addresses the value // (to satisfy possible pointer methods) and continues to dereference // subsequent pointers as necessary. // // After the first round-trip, we set v back to the original value to // preserve the original RW flags contained in reflect.Value. v0 := v haveAddr := false // If v is a named type and is addressable, // start with its address, so that if the type has pointer methods, // we find them. if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { haveAddr = true v = v.Addr() } for { // Load value from interface, but only if the result will be // usefully addressable. if v.Kind() == reflect.Interface && !v.IsNil() { e := v.Elem() if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { haveAddr = false v = e continue } } if v.Kind() != reflect.Pointer { break } if decodingNull && v.CanSet() { break } // Prevent infinite loop if v is an interface pointing to its own address: // var v interface{} // v = &v if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { v = v.Elem() break } if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } if v.Type().NumMethod() > 0 && v.CanInterface() { if u, ok := v.Interface().(Unmarshaler); ok { return u, nil, reflect.Value{} } if !decodingNull { if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { return nil, u, reflect.Value{} } } } if haveAddr { v = v0 // restore original value after round-trip Value.Addr().Elem() haveAddr = false } else { v = v.Elem() } } return nil, nil, v }
感觉 java 感觉清爽很多. java 感觉不需要学, 看看 ArrayList HashMap 这些接口就可以写了,语法也比较简单. golang 真是各种奇技淫巧满天飞.
![]() | 1 Nazz 2023-02-23 13:24:31 +08:00 via Android ![]() interface 了解下 |
![]() | 2 NeoZephyr 2023-02-23 13:25:20 +08:00 ![]() 说真的,看到这种满屏的 v, i, e 变量,就想吐 |
![]() | 3 echoless OP ![]() @NeoZephyr 官方源代码, 可不是我写的. 我也是吐, 有些同事把 golang 这种风格弄到 python 里面, 看到我就... |
![]() | 4 echoless OP 另外求 golang 的资料, 中级水平的, 准备去卷 golang 了. 感觉 python 工作工资越来越不行了. |
5 SuperManNoPain 2023-02-23 13:35:21 +08:00 ![]() 大道至简,滑稽.jpg |
![]() | 6 liuxu 2023-02-23 13:38:59 +08:00 ![]() |
7 WispZhan 2023-02-23 13:41:51 +08:00 via Android ![]() Java 是语法最简单、最嗦的编程语言 |
![]() | 8 echoless OP @liuxu 上段代码里面的 v, u 我倒是没有意见. 因为也不好找一个合适的命名. 但是有些地方, 比如输入参数是 car Car, 那么命名弄个 c 就是恶心人了. |
9 fo0o7hU2tr6v6TCe 2023-02-23 13:43:23 +08:00 ![]() type Model struct { /td> Name string `json:"name"` Price interface{} `json:"price"` Location string `json:"location"` Image string `json:"image"` } func ParseModel() []Model { str := `[{ "name": "Abyssin", "price": 500, "location": "Lviv", "image": "https://olxua-ring02.akamaized.net/images_slandocomua/476948786_2_1000x700_abissenysh-chempion-fotografii.jpg" }, { "name": "Abyssin", "price": "550", "location": "Lviv", "image": "https://olxua-ring10.akamaized.net/images_slandocomua/342850976_3_1000x700_abidetki-koti_rev006.jpg" }]` var models []Model err := json.Unmarshal([]byte(str), &models) if err != nil { panic(err) } return models } func main() { items := ParseModel() fmt.Println(items) } |
![]() | 10 echoless OP 上面的问题主要是各种 reflect, 看晕了. 还有 reflect.Zero MakeSlice 这种, 可能是用的少吧, 看起来抽象 |
![]() | 12 RICKEYGONG 2023-02-23 13:56:01 +08:00 @liuxu 赞同 |
13 coderxy 2023-02-23 13:59:27 +08:00 ![]() go 如果你读不明白,java 你大概率也读不明白的。 |
![]() | 14 8355 2023-02-23 14:09:01 +08:00 喜欢 java 和 go 的本质上就是两种人 写 java 循规蹈矩建一堆文件起长长的名字 xml 真的很刺激 假如没有注解 |
15 fo0o7hU2tr6v6TCe 2023-02-23 14:10:45 +08:00 @wuhaoecho mapstructure 这个库里有个 example 可以看一下 https://pkg.go.dev/github.com/mitchellh/mapstructure?utm_source=godoc Example (WeaklyTypedInput) 我个人觉得, 如果你要改的话,reflect 是逃不过的,java 里面不是通过反射去修改的么 0.0 ,python 里面确实没有这个考虑 |
![]() | 16 echoless OP @hzjseasea ``` items := ParseModel() for _, v := range items { switch v.Price.(type) { case float64: fmt.Printf("%+v\n", int(reflect.ValueOf(v.Prce).Float()))。// 草草草 case string: fmt.Println(v.Price) default: panic("unknown type") } // if reflect.TypeOf(v.Price) == reflect.Kind.String() { // fmt.Printf("%d\n", v.Price) //} } ``` 差不多这样, 吐槽归吐槽, 你的 interface 倒是提供了一个思路. 但是还不够优雅. 最好是我每个 attribute 能提供一个函数去解析. python 弱类型, 比较方便. |
![]() | 17 lyz1990 2023-02-23 14:17:27 +08:00 ![]() 解析 json 还得看我大 PHP 和 JS 啊,哈哈 |
18 tuxz 2023-02-23 14:17:54 +08:00 ![]() 可以自定义实现 struct 的反序列化,参考这个 https://attilaolah.eu/2013/11/29/json-decoding-in-go |
![]() | 19 zjsxwc 2023-02-23 14:19:16 +08:00 ![]() 不会吧,golang 解析 json 时居然没有注解能够处理某一个 json 字段可能有多个类型, 但 rust 可以通过注解这么弄: https://stackoverflow.com/questions/37870428/convert-two-types-into-a-single-type-with-serde#answer-37871403 ```rust #[derive(Clone, Debug, Deserialize)] struct Points { #[serde(deserialize_with = "deserialize_u64_or_empty_string")] x: u64, #[serde(deserialize_with = "deserialize_u64_or_empty_string")] y: u64, name: String, } struct DeserializeU64OrEmptyStringVisitor; impl<'de> de::Visitor<'de> for DeserializeU64OrEmptyStringVisitor { //处理 包含字符串或 u64 的字段 } ``` |
![]() | 20 MoYi123 2023-02-23 14:19:48 +08:00 @NeoZephyr 麻烦解释一下 https://github.com/alibaba/fastjson/blob/436cae79bfb327f3641ac4c901e9411fc827b415/src/main/java/com/alibaba/fastjson/parser/JSONLexerBase.java#L41 这里的 ch,sp,bp,np 都是什么意思? 解 json 的代码和业务代码是一回事吗? |
![]() | 21 Macolor21 2023-02-23 14:21:30 +08:00 ![]() @liuxu #6 后面的怎么不截了? 1. 驼峰不允许,写、看 Linux 内核的人,大部分都是 C ,之前的字体可能会大小写不敏感,或者没有等宽字体吧,这是风格问题 2. 局部变量尽量简便,如果 for loop 里面的 index 这种可以简化为 i. 因为它在这里不难理解. 3. 匈牙利命令法:太嗦了,没几个人会用 4. 全局变量、函数应该有小写的描述名,适当用下划线区分。一个全局函数叫 `atty()` 也被骂啊,人家要求写成 `get_active_tty()` 还骂这是 Linux 不是 BSD 说白了,就是风格统一的问题,Linux 源码有自己的一套风格( c 语言用户群用的风格),拿其他语言的风格上去提交代码,不是找骂么。你在 Java 里写 get_active_tty() 我也觉得你是傻逼。 第二的问题,Java 里 Foreach 一个集合,也是 collection.foreach(e-> e.printf()); 用 e 或者 ele 代替 elements. 命名风格无法决定语言嗦不嗦,而是语法糖、特性( Pattern match 、类型推断、类型定义)决定,如果你认为命令风格是 Java 被诟病的原因,只能说你的水平太低,只能当个 reader 和传话太监。 连命令风格都不知道,要么网管转维的半吊子,要么销售培训转开发的半吊子。 |
24 a132811 2023-02-23 14:43:21 +08:00 1. 这不是 golang 本身的问题。golang 自带的这个 json 库封装时就没有支持多类型自动转换。 2. 语言风格、习惯其实没有什么好喷的,有人就是喜欢这种简化,有人就是喜欢冗长风格,争论不会任何结果。 3. 不过 golang 有一点好就是源码修改和调试非常的方便。有精力的话,可以给官方提一个 PR |
![]() | 25 erichen86 2023-02-23 14:44:25 +08:00 python 为什么这么流行,代码看着也挺难受的,感觉还不如 go 看的舒服 |
![]() | 26 yaott2020 2023-02-23 14:44:27 +08:00 via Android @zjsxwc 你可以自己在 github 提个 issue ,或者自定义解析函数,字段多类型可以用 any(interface{}) |
![]() | 27 rrfeng 2023-02-23 14:45:30 +08:00 ![]() type IntStr int64 type Model struct { Price IntStr } func (IntStr) Unmarshal(){ ... } |
![]() | 28 wangsongyan 2023-02-23 14:50:13 +08:00 json.Number |
29 dobelee 2023-02-23 15:03:53 +08:00 value -> v element -> e 没看出有任何问题。 |
30 xiaocaiji111 2023-02-23 15:04:03 +08:00 ![]() 底层源码是不好看的,不看底层学起来是蛮简单。短变量命名,真的是,有时候源码过长,前面读了后面就忘了啥意思(局部变量用一下的能短则短),还是 java 那样嗦点儿好。毕竟是给人看的,看懂最重要。 |
![]() | 31 liuxu 2023-02-23 15:04:43 +08:00 ![]() @wuhaoecho 参数就算是 c 也肯定是也要写清楚的,但也不会写成 myFirstCar, mySecondCar 这种,不过 rust 和 golang 这种可以用闭包的,参数用 k,v 简写也正常,闭包本身建议代码不要太复杂 楼上还有一个急的跳脚开始疯狂瞎咬人的我就不 at 了,免得把你这帖子搞的水深火热了,我就是在说 go,c,java 各有各的风格,他连基本的阅读理解能力都没有,就有一些人非要拿 java 的风格往 linux 内核里面搞,截图后面的是 linux 向 bsd 开炮,话题就撤太远了 醉舞经楼半卷书,坐井谈天阔 |
![]() | 32 fgwmlhdkkkw 2023-02-23 15:13:28 +08:00 你自定义一个 Price 类型,不久好了吗? 现实世界就是这么复杂,你换什么语言都要面对的啊? |
![]() | 34 echoless OP @rrfeng @fgwmlhdkkkw ``` type IntStr struct { value int } type Model struct { Name string `json:"name"` Price IntStr `json:"price"` Location string `json:"location"` Image string `json:"image"` } func (v *IntStr) UnmarshalJSON(b []byte) (err error) { s, n := "", float64(0) if err = json.Unmarshal(b, &s); err == nil { intVar, _ := strconv.Atoi(s) v.value = intVar return } if err = json.Unmarshal(b, &n); err == nil { v.value = int(n) } return } ```` 搞定, 还行了. v 友牛皮 |
![]() | 35 realpg PRO 我就搞不懂为啥还要规定变量命名风格。。。 无论啥语言 |
36 a132811 2023-02-23 16:24:33 +08:00 ![]() @wuhaoecho 没必要用结构体 ``` type StrInt int func (v *StrInt) UnmarshalJSON(b []byte) (err error) { s, n := "", float64(0) if err = json.Unmarshal(b, &s); err == nil { intVar, _ := strconv.Atoi(s) *v = StrInt(intVar) return } if err = json.Unmarshal(b, &n); err == nil { *v = StrInt(n) } return } ``` |
![]() | 37 echoless OP |
![]() | 38 GG668v26Fd55CP5W 2023-02-23 16:29:11 +08:00 从动态语言过来的看到这 json 处理感觉有点呆 |
![]() | 39 virusdefender 2023-02-23 16:32:33 +08:00 json.Number 就是来干这个的 |
![]() | 40 vcbal 2023-02-23 16:39:44 +08:00 有没有想过这是你自己的原因? |
![]() | 41 echoless OP 我把完整的代码列出来 https://go.dev/play/p/8sFRipQ1hAn 就处理一个 json 要用到懂 1. interface (golang 默认的, 否则不了解 UnmarshalJSON 咋回事, 这个看文档是最简单的途径, 目前我还没有入门怎么看 golang 文档最快, 容易晕) 2. pointer 这玩意有时候容易晕, 比 c 容易, 但是跟 java, python 比是复杂了. 3. type 声明 或者 struct ``` type StrInt int type IntStr struct { value int } ``` 总体看上来, 没觉得哪里比其他语言简单. 上面有人讲, 你用别的语言(强类型)也一样的复杂度. 但是别的语言不像 golang 这种, 宣扬 less is more. |
![]() | 43 guyanyouyou 2023-02-23 16:44:09 +08:00 ![]() @wuhaoecho 学好以后发现,在 golang 的擂台上,不仅看到了原来在 python 擂台一起卷的朋友,还有前端、PHP 和 Java 的小伙伴 |
44 dongtingyue 2023-02-23 17:22:03 +08:00 json 这方面确实不如 js 方便 |
![]() | 45 fregie 2023-02-23 17:50:54 +08:00 没有语言是万能的,如果你觉得在某个方面 go 不好用,那么你就不该用 go 来做. 明明 go 都不是一个面向对象的语言,非要和面向对象的语言比写业务,这才是出问题的地方 |
![]() | 46 ethsol 2023-02-23 18:05:08 +08:00 ![]() 只有 #39 是老实人 |
![]() | 47 bxb100 2023-02-23 18:21:35 +08:00 rust 杀手锏 json -> struct |
![]() | 48 gogorush 2023-02-23 18:59:28 +08:00 golang 说 别跟我谈 JSON 和 MySQL 的 ORM 不然我发火了 |
50 sealinfree 2023-02-23 21:08:15 +08:00 @a132811 赞,学习了 |
51 lixintcwdsg 2023-02-23 21:20:19 +08:00 ![]() 写代码 10 多年了哈 js as ts java php python bash 都写过一些,java 写的尤其多 架构什么的也都搞 go 的问题很早就和人讲过了,和过去 node.js 其实类似,因为标准轮子还是太少,各种私人写的又很重要的框架、工具很多,这个实际上会有大问题。维护起来更麻烦。 java 最大的好处就是 web 开发东西都很明确 spring 解决大部分问题,其余一些通用的解决其他问题,所以写出来东西都类似,谁接手都没啥问题。 |
![]() | 52 panlatent 2023-02-23 22:46:56 +08:00 ![]() 毕业后经过 PHP -> Go -> (C# ...) -> C++(重学) 这么学一圈。对 Go 的理解就是 Better C ,至于语法,各有权衡,各有取舍,但不一定都是精心设计出来的(专指) :D |
53 jeesk 2023-02-23 23:46:00 +08:00 觉得 java 好阅读的可以看看 google juice 的代码。觉得 golang 好读的可以看看 docker 的代码。 |
![]() | 55 hzxxx 2023-02-24 01:07:48 +08:00 估计还没到呢,Java boy ,等你再学 protoc 、orm 、wire 、还有微服务,你就会怀念以前 spring 全家桶梭哈的日子了 |
![]() | 56 WilliamYang 2023-02-24 01:53:17 +08:00 你不够了解 Golang 而已,json.Number ,json.RawMessage 了解一下 |
![]() | 57 Nazz 2023-02-24 07:51:07 +08:00 via Android 刚学 go 的时候我也很疑惑,json_encode, json_decode 和万能的 array 用习惯了而已 |
58 jorneyr 2023-02-24 09:37:33 +08:00 写了一年 Go ,终于习惯了 Go 的写法,Java 和 Go 已经可以平滑切换。 |
59 naturekingfree 2023-02-24 09:39:16 +08:00 @NeoZephyr 我也是 |
![]() | 60 macscsbf 2023-02-24 09:51:50 +08:00 ![]() 你说说看哪里难阅读了,不然我也不知道怎么去解答你的疑问 |
61 DamonLin 2023-02-24 10:14:37 +08:00 java 和 php 直接梭哈哈哈哈,没有这个烦恼 |
![]() | 62 gzxy 2023-02-24 10:43:06 +08:00 |
![]() | 63 ZeroDu 2023-02-24 11:02:40 +08:00 String str = "A" int i = 1 在其他语言里面可能直接 i+str 就行了。然而在 go 里面居然还要引入一个 strconv 包来转换在拼接 |
![]() | 64 vipppppp 2023-02-24 14:25:13 +08:00 Go 开发者,Go json, error 都让我很头疼,基本实现不了好的 AOP 方式也很难受。。 但是并发编程的价值远远大于这些让我头疼的点。。。 |