To encode and decode iter.Seq using JSON, one way is to implement the json.Marshaler and json.Unmarshaler interfaces for iter.Seq . Here's an example implementation:
func (s Seq[V]) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
buf.WriteByte('[')
first := true
for v := range s {
if !first {
buf.WriteByte(',')
}
first = false
bytes, err := json.Marshal(v)
if err != nil {
return nil, err
}
buf.Write(bytes)
}
buf.WriteByte(']')
return buf.Bytes(), nil
}
func (s *Seq[V]) UnmarshalJSON(bytes []byte) error {
var vs []V
if err := json.Unmarshal(bytes, &vs); err != nil {
return err
}
*s = Iter(vs)
return nil
}
9条答案
按热度按时间46scxncf1#
如何实现这个?
显然是不可能的。
9rbhqvlz2#
好的,通过反射是可能的,参见#61897(评论)
pwuypxnk3#
我希望有一个通用的API,可以动态地表示与Go切片或Map在语义上等价的类型,因此像链表或B树这样的容器类型不需要自定义
MarshalJSON
和UnmarshalJSON
方法。为了实现这一点,我期望:Marshal
和Unmarshal
。目前,提案仅适用于Marshal
,但我认为我们也需要为Unmarshal
找到一个解决方案。zi8p0yeb4#
@gophun,建议的实现using
reflect.Value.Call
would have poor performance。除了我对marshal和unmarshal之间不对称的担忧,我们还需要在"reflect"中提供一流的支持或优化,以使迭代快速进行。lx0bsm1f5#
To encode and decode
iter.Seq
using JSON, one way is to implement thejson.Marshaler
andjson.Unmarshaler
interfaces foriter.Seq
.Here's an example implementation:
This implementation allows
iter.Seq
to be marshaled into JSON format and unmarshaled from JSON format seamlessly.https://go.dev/play/p/Jqg81JhEr9_f?v=gotip
nimxete26#
作为一个合适的解决方案,我期望以下属性:
[]V
并忽略任何支持迭代器的后备存储。iter.Seq
对这些都有特殊知识。flvlnr447#
迭代器,就像我们现在(实验性地)拥有的它们(即
iter.Seq
),是单向和只读的(C中称为“输入迭代器”),这就是为什么我只提到了 Marshal 而不是 Unmarshal。要解组,我们需要类似于 C 的 Output Iterator 的东西,然后我们可以使用一个类似于
back_insert_iterator
的(我们可能会称之为“追加”而不是“后插入”)。一旦我们有了这个,我可以想象出类似于json.Decoder.UseNumber()
的东西来定义自定义的解组数组的方式。值得思考,但超出了本票据的范围,我认为。smtd7mpg8#
然后再说一次,使Marshall和Unmarshal不对称也不是很好。例如,让我们看看由protoc为grpc/protobuf生成的类型。当我发起请求时,我希望能够传递一个
seq.Iter
字段给repeated
字段。但是当我接收一个请求时,切片更方便,因为我可以在遍历它之前检查它的长度。此外,改变这一点将是一个破坏性的改变。这是否意味着protoc需要为发送和接收生成每个消息的两个不同版本?这似乎并不可取。如果我只想将(部分)传入的消息转发到另一个服务,我不想先转换它。
1cklez4t9#
原则上,可以返回一个在消耗数组的流式方式中关闭的
iter.Seq
: https://go.dev/play/p/6G4GTrHMNo4?v=gotip但当然,第一轮迭代器只支持不可错的迭代器,因此任何尝试延迟进行 JSON 解析都可能导致无法处理的错误。
原则上,它可以先调用
json.Valid
来找到可能错误的子集,然后再开始迭代,但这会牺牲两次遍历令牌。即使这样还不够,因为语法上有效的值内部可能与类型V
不兼容。据我所知,唯一解决这个问题的方法是首先进行完整的解析,然后将结果缓存到内存中以便在迭代过程中返回。这样做可能(但不一定)相对于在迭代过程中再次解析更有优势。🤷♂️对我来说,这只是不支持可错迭代器的一个自然后果:对于可以动态失败的事情,不适合使用迭代器抽象,而 JSON 解析可以动态失败。
(我承认这种替代方法也是针对 JSON 的特定方法,因此无法在多种序列化格式上泛化,但我认为在考虑任何除 JSON 之外的格式之前,无法处理错误就使这种方法失去了资格。)