要解析的 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 2
interface 了解下
|
2
NeoZephyr 2023-02-23 13:25:20 +08:00 2
说真的,看到这种满屏的 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 1
大道至简,滑稽.jpg
|
6
liuxu 2023-02-23 13:38:59 +08:00 22
|
7
WispZhan 2023-02-23 13:41:51 +08:00 via Android 2
Java 是语法最简单、最啰嗦的编程语言
|
8
echoless OP @liuxu 上段代码里面的 v, u 我倒是没有意见. 因为也不好找一个合适的命名. 但是有些地方, 比如输入参数是 car Car, 那么命名弄个 c 就是恶心人了.
|
9
fo0o7hU2tr6v6TCe 2023-02-23 13:43:23 +08:00 1
type Model struct {
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 1
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.Price).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 3
解析 json 还得看我大 PHP 和 JS 啊,哈哈
|
18
tuxz 2023-02-23 14:17:54 +08:00 1
可以自定义实现 struct 的反序列化,参考这个 https://attilaolah.eu/2013/11/29/json-decoding-in-go
|
19
zjsxwc 2023-02-23 14:19:16 +08:00 1
不会吧,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 10
@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 1
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 2
底层源码是不好看的,不看底层学起来是蛮简单。短变量命名,真的是,有时候源码过长,前面读了后面就忘了啥意思(局部变量用一下的能短则短),还是 java 那样啰嗦点儿好。毕竟是给人看的,看懂最重要。
|
31
liuxu 2023-02-23 15:04:43 +08:00 1
@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 2023-02-23 16:08:26 +08:00
我就搞不懂为啥还要规定变量命名风格。。。
无论啥语言 |
36
a132811 2023-02-23 16:24:33 +08:00 3
@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
falcon05 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 2
@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
zong400 2023-02-23 18:05:08 +08:00 2
只有 #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 1
写代码 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 1
毕业后经过 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 1
你说说看哪里难阅读了,不然我也不知道怎么去解答你的疑问
|
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 方式也很难受。。
但是并发编程的价值远远大于这些让我头疼的点。。。 |