你正在使用的Go版本是什么( go version
)?
$ go version
go version go1.15rc1 linux/amd64
这个问题在最新版本中是否会重现?
是的
你正在使用什么操作系统和处理器架构( go env
)?
go env
输出
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/alvaro/.gocache"
GOENV="/home/alvaro/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/alvaro/git/golang/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/alvaro/git/golang"
GOPRIVATE=""
GOPROXY="direct"
GOROOT="/usr/local/go"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build855135854=/tmp/go-build -gno-record-gcc-switches"
你做了什么?
构建了一个自定义的 json.Unmarshaler
来默认一个配置文件,然后使用了一个 json.Decoder
与 DisallowUnknownFields
来解析一个具有额外未知字段的json表示。我原以为这会失败,但它没有。
https://play.golang.org/p/8cEJU-Y0-9L
你期望看到什么?
一个错误,指出json文档中的未知、额外字段
你实际上看到了什么?
没有错误
9条答案
按热度按时间cqoc49vn1#
当你在
UnmarshalJSON
方法中调用json.Unmarshal
时,它会创建一个新的decodeState
,这个新示例对顶层的json.Decoder
示例一无所知。如果你想在未知字段上出错,你需要在你json.Unmarshaler
实现中强制执行这一点。bd1hkmkf2#
当你在UnmarshalJSON方法中调用json.Unmarshal时,它会创建一个新的decodeState,这个decodeState并不知道顶层的json.Decoder示例。如果你想在未知字段上出错,你需要在你实现的json.Unmarshaler中强制执行这一点。
我知道这一点,但我不想一般地强制执行。我希望使用顶层
json.Decoder
示例中的设置,似乎很难找到这一点(或者我漏掉了什么?)yv5phkfx3#
这里的问题是,
json.Unmarshaler
没有内置对选项的支持,所以在当前API中没有很好的方法来解决这个问题。如果你愿意的话,你可以自己记住选项并在嵌套的Unmarshal/Decode调用中重新应用它们。我认为在当前API中没有一种方法可以在不重复多个代码块或完全破坏它的情况下修复这个问题,而这在Go 1.x中并不是一个选项。我最近整理了一下关于编码/json重构的想法,如果你感兴趣的话,选项的问题几乎排在列表的最前面。
pprl5pva4#
这里的问题是,json.Unmarshaler没有内置对选项的支持,所以用当前的API无法很好地解决这个问题。如果你愿意的话,可以自己记住这些选项,并在嵌套的Unmarshal/Decode调用中重新应用它们。
我无法控制所有调用
Unmarshal
的代码,所以我真的没有办法记住这个,或者还有其他方法吗?这个问题基本上是关于以某种方式更改API,以便能够传递这些选项,例如通过一个额外的、可选的接口(
UnmarshalerWithOptions
?)。我对它应该是什么样子的意见不多,但我想确认我的怀疑,那就是今天这是不可能的,并且希望对此有一个跟踪问题。zsbz8rwp5#
我猜想这已经存在一个问题,但我现在真的找不到它。可选地扩展接口是一个选择,但老实说不是一个很好的选择——然后你把问题转移到修复所有实现以做正确的事情上,这也增加了相当多的代码更改,几乎就像切换到v2 API一样。
mlnl4t2r6#
可选地扩展接口是一个选项,但老实说,这并不是一个很好的选择——然后你把问题转移到修复所有实现以做正确的事情上,这也增加了相当多的代码更改,几乎就像切换到v2 API一样。
如前所述,我对这个应该看起来如何没有太多意见,但我想象一下,v2 API设计将需要很长时间,而我更希望在可预见的未来有一个不太好的解决方案,而不是在非常遥远的未来有一个很好的解决方案(另外,向当前API添加一些内容不会阻止我们在v2 API中实现一些合适的东西)
lvjbypge7#
事实上,重新设计可能需要一段时间。
不好的解决方案的问题在于,有时候它们比什么都不做还要糟糕,我认为目前的共识是基本上冻结编码/json API不变。你可以查看所有冻结的json提案作为例子。@rsc@dsnet可能能够以比我更有权威的方式确认:)
如果你想提议向包API添加内容,那么你应该将其变成一个提案,并像任何其他提议的API更改一样进行审查。你可以重用这个问题,或者另开一个新问题。参见https://github.com/golang/proposal
qhhrdooz8#
正如@mvdan提到的,我不知道是否有关于顶级选项传递问题的特定问题,但这是我在许多不同的
encoding/json
问题中评论过的一个问题。添加新功能需要O(n!)的维护成本,因为你需要考虑如何与已经提供的所有功能进行交互(以及这些功能的全部可能组合)。我认为在仔细思考影响之前,我们不应该添加另一个UnmarshalerWithOptions
接口。作为一个高级概述,这样的接口可能需要依赖于encoding/json
包,这已经与Unmarshaler
接口本身产生了显著的分歧(它除了基本类型(如[]byte
、int
和error
)之外没有任何依赖关系)。如果我们通过接口强制这种依赖关系,那么是否应该让接口提供比选项更多的东西也成了一个问题。例如,目前调用嵌套的Unmarshaler
是O(n^2),因为encoding/json
包必须重复解析整个子树,才能在调用UnmarshalJSON
之前找到JSON令牌的结束位置。如果我们能传递类似于json.Decoder
的东西,可能会更有效。eqzww0vc9#
大家好,我们启动了一个讨论这个提案精神的项目。在v2中,我们提议支持以下接口:
特别需要注意的是,这传递了一个
Options
值,可以保留DisallowUnknownFields
语义。现有的
UnmarshalJSON
方法显然无法受益,但实现UnmarshalJSONV2
方法的类型可以在将来受益。