感觉 golang 比 Java 还难读, 难学

2023-02-23 13:20:57 +08:00
 echoless

要解析的 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 真是各种奇技淫巧满天飞.

7807 次点击
所在节点    程序员
65 条回复
Nazz
2023-02-23 13:24:31 +08:00
interface 了解下
NeoZephyr
2023-02-23 13:25:20 +08:00
说真的,看到这种满屏的 v, i, e 变量,就想吐🤮
echoless
2023-02-23 13:27:56 +08:00
@NeoZephyr 官方源代码, 可不是我写的. 我也是吐, 有些同事把 golang 这种风格弄到 python 里面, 看到我就...
echoless
2023-02-23 13:33:45 +08:00
另外求 golang 的资料, 中级水平的, 准备去卷 golang 了. 感觉 python 工作工资越来越不行了.
SuperManNoPain
2023-02-23 13:35:21 +08:00
大道至简,滑稽.jpg
liuxu
2023-02-23 13:38:59 +08:00
一般不是从 C 学起,没看过大型 C 项目的是对这种写法不适应

特别是有极少部分 javaer 喜欢拿 java 的格式挑其他语言,不然《 linux 内核设计与实现》作者这种级别的大佬也不会专门在书的最后喷 javaer ,太惹人厌了

WispZhan
2023-02-23 13:41:51 +08:00
Java 是语法最简单、最啰嗦的编程语言
echoless
2023-02-23 13:42:00 +08:00
@liuxu 上段代码里面的 v, u 我倒是没有意见. 因为也不好找一个合适的命名. 但是有些地方, 比如输入参数是 car Car, 那么命名弄个 c 就是恶心人了.
fo0o7hU2tr6v6TCe
2023-02-23 13:43:23 +08:00
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)
}
echoless
2023-02-23 13:44:12 +08:00
上面的问题主要是各种 reflect, 看晕了. 还有 reflect.Zero MakeSlice 这种, 可能是用的少吧, 看起来抽象
echoless
2023-02-23 13:50:28 +08:00
@hzjseasea 多谢, 这个解决了解析的问题, 但是我这个 price 还是要转换成 int64
RICKEYGONG
2023-02-23 13:56:01 +08:00
@liuxu 赞同
coderxy
2023-02-23 13:59:27 +08:00
go 如果你读不明白,java 你大概率也读不明白的。
8355
2023-02-23 14:09:01 +08:00
喜欢 java 和 go 的本质上就是两种人
写 java 循规蹈矩建一堆文件起长长的名字 xml 真的很刺激
假如没有注解🙅 🙅 🙅
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 里面确实没有这个考虑
echoless
2023-02-23 14:15:04 +08:00
@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 弱类型, 比较方便.
lyz1990
2023-02-23 14:17:27 +08:00
解析 json 还得看我大 PHP 和 JS 啊,哈哈
tuxz
2023-02-23 14:17:54 +08:00
可以自定义实现 struct 的反序列化,参考这个 https://attilaolah.eu/2013/11/29/json-decoding-in-go
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 的字段
}
```
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 的代码和业务代码是一回事吗?

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

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

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

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

© 2021 V2EX