<p>I know that this is possible when you are dealing with defined structs, using structures that wrap other structures. However, I have a function that is returning an <code>interface{}</code>. All I know about the <code>interface{}</code> is that it is JSON encodable. I would like to add a timestamp field to the output when I Marshal the object.</p>
<pre><code>package main
import "encoding/json"
import "fmt"
func Encode(data interface{}) {
output, _ := json.Marshal(struct{
Data interface{}
Timestamp int `json:"ts"`
}{data, 3})
fmt.Println(string(output))
}
func main() {
x := map[string]int{"arbitrary":6}
// I want this to print {"arbitrary": 6, "ts": 3}
Encode(x)
// It actually prints {"Data":{"arbitrary":6}, "ts":3}
}
</code></pre>
<p>Is there some way to get rid of the "Data" key and have the "ts" key be at the same level as the fields in data?</p>
<hr/>**评论:**<br/><br/>binaryblade: <pre><p>Because that interface could be an array or otherwise it may be tricky. Although you can try embedding the interface instead.</p></pre>TheMerovius: <pre><p>Embedding won't help. The <a href="https://godoc.org/encoding/json#Marshal" rel="nofollow">encoding rules</a> state that embedded interface types are always keyed.</p></pre>whizack: <pre><p>If you changed 'data' to a map[string]interface{} then you could append your own key to the data before you encode it.</p></pre>Eggbert345: <pre><p>Yeah I thought of that, except the data I'll be dealing with will be all different structs. And I don't want to reflect over the struct fields to pull them into a new map[string]interface{}, that just seems like doing double duty with <code>encoding/json</code> and not really performant.</p></pre>whizack: <pre><p>if you can guarantee they are all structures (and not just raw slices or values), you could do something like this: <a href="https://play.golang.org/p/AXoh1fQYyp" rel="nofollow">https://play.golang.org/p/AXoh1fQYyp</a></p></pre>TheMerovius: <pre><p>I don't think there is any way to reliably do that, except with reflection. You could try something like <code>str = "{\"timestamp\": 123456789," + str[1:]</code> with <code>str</code> being the json encoding of the value. But that would break if the encoded value itself contains a field <code>timestamp</code>. Or if the encoded value is an array, instead of an object (or even a string, number,boolean…).</p></pre>TheMerovius: <pre><p>Another way would be to encode, decode into map[string]interface{}, adding timestamp, encode.</p></pre>xargon7: <pre><p>You should check the encoded result to see if it marshals to a JSON object. Reflection isn't likely to give you the right result because the underlying object could implement JSONMarshaller even if it's a int.</p>
<p>Something like this: <a href="http://play.golang.org/p/ZT-O2h4zfo" rel="nofollow">http://play.golang.org/p/ZT-O2h4zfo</a></p></pre>TheMerovius: <pre><blockquote>
<p>Reflection isn't likely to give you the right result because the underlying object could implement JSONMarshaller even if it's a int.</p>
</blockquote>
<p>The json-package only uses reflection itself. So I disagree with this statement. In fact, the simplest and most robust way to do what OP wants is probably to copy-paste the relevant parts of json and then add the code in there directly.</p></pre>xargon7: <pre><blockquote>
<p>The json-package only uses reflection itself. So I disagree with this statement.</p>
</blockquote>
<p>Let me clarify: Using only reflection gives you no guarantees on whether the resulting encoded data corresponds to a JSON object. You have to <em>actually marshal</em> the data (in the general case) and inspect the result -- which is exactly what you were saying: </p>
<blockquote>
<p>In fact, the simplest and most robust way to do what OP wants is probably to copy-paste the relevant parts of json and then add the code in there directly.</p>
</blockquote>
<p>Agreed -- that what I did in my snippet above.</p></pre>Eggbert345: <pre><p>I see what you both are saying. However I know that the data will be a struct with JSON tags, I just don't know which one. I was hoping there would be a solution that wouldn't require me to copy the JSON library.</p></pre>xargon7: <pre><p>Take a look at the link I posted -- it's very efficient, simple, and generic, and you can explicitly handle a non-struct JSON result however you like.</p></pre>xargon7: <pre><p>By the way, an important caveat: If the structure that you are marshaling already has a "ts" field, then you will end up with two "ts" fields in the generated struct. This is valid JSON, but the Go code won't know what to do with it and will probably corrupt your data when you decode it. Most language libraries have inconsistent handling of repeated keys in JSON data.</p></pre>izuriel: <pre><p>I know this off topic would it seem,given that JSON is a subset of JavaScript, that there should be a very clear way of handling duplicate keys -- the last value applies. </p></pre>thepciet: <pre><p>JSON objects are not maps! Duplicate names (keys) are a feature.</p>
<blockquote>
<p>An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).</p>
</blockquote>
<p><a href="http://www.json.org/" rel="nofollow">http://www.json.org/</a></p></pre>izuriel: <pre><p>I was getting at this part of the person I replied to:</p>
<blockquote>
<p>... Most language libraries have inconsistent handling of repeated keys in JSON data.</p>
</blockquote>
<p>Because in my experience it's never really been a problem. Let me just try it real quick...</p>
<p>Ruby handles it gracefully... the last value.</p>
<pre><code>>> require "json"
=> true
>> JSON.parse('{"one": 1, "two": 2, "one": 3}')
=> {"one"=>3, "two"=>2}
</code></pre>
<p>Python handles it as expected...</p>
<pre><code>>>> import json
>>> json.loads('{"one": 1, "two": 2, "one": 3}')
{u'two': 2, u'one': 3}
</code></pre>
<p>Node (or JavaScript) handles it as expected...</p>
<pre><code>> JSON.parse('{"one": 1, "two": 2, "one": 3}')
{ one: 3, two: 2 }
</code></pre>
<p>And of course Go gracefully handles it as would be expected... <a href="http://play.golang.org/p/h_Fjd-zjp5" rel="nofollow">http://play.golang.org/p/h_Fjd-zjp5</a> (both with a map and with a struct).</p>
<p>So it's as a I thought, duplicate keys are no worries. Just now that the most recent value associated to a key is the one that matters.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传