<p dir="auto">Original discussion at <a href="https://groups.google.com/forum/#!searchin/golang-dev/json$20map/golang-dev/5gSHNrJQpUI/vZGSGRmUrC0J" rel="nofollow">https://groups.google.com/forum/#!searchin/golang-dev/json$20map/golang-dev/5gSHNrJQpUI/vZGSGRmUrC0J</a></p>
<p dir="auto">Currently, json.Marshal will fail to marshal Go maps that have non-string keys, e.g.:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="// http://play.golang.org/p/2m9wLZATqw
type Coord struct { X,Y int }
occupied := map[Coord]bool{}
occupied[Coord{1,2}] = true
data, err := json.Marshal(occupied)
fmt.Printf(&quot;Data: %s\nErr: %v&quot;, data, err)"><pre class="notranslate"><code class="notranslate">// http://play.golang.org/p/2m9wLZATqw
type Coord struct { X,Y int }
occupied := map[Coord]bool{}
occupied[Coord{1,2}] = true
data, err := json.Marshal(occupied)
fmt.Printf("Data: %s\nErr: %v", data, err)
</code></pre></div>
<p dir="auto">I propose to enhance the encoding/json package such that:</p>
<ol dir="auto">
<li>for <code class="notranslate">json.Marshal</code>
<ul dir="auto">
<li>If the map key is a string kind it is used directly.</li>
<li>Otherwise if the map key satisfies the encoding.TextMarshaler interface then that is used to generate the map key.</li>
<li>Otherwise it fails as it does today.</li>
</ul>
</li>
<li>for <code class="notranslate">json.Unmarshal</code>
<ul dir="auto">
<li>If the map key is a string kind it is written directly.</li>
<li>Otherwise if the map key satisfies the encoding.TextUnmarshaler interface then that is used to decode the map key.</li>
<li>Otherwise it fails as it does today.</li>
</ul>
</li>
</ol>
<h1 dir="auto">Example</h1>
<p dir="auto">(<a href="http://play.golang.org/p/VxhFluFKTX" rel="nofollow">http://play.golang.org/p/VxhFluFKTX</a>)</p>
<p dir="auto">This would, for example, allow a <code class="notranslate">map[Coord]bool</code> to be Marshaled &amp; Unmarshaled if <code class="notranslate">Coord</code> was defined as:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type Coord struct{ X, Y int }
func (c Coord) MarshalText() ([]byte, error) {
    return []byte(fmt.Sprintf(&quot;%d,%d&quot;, c.X, c.Y)), nil
}
func (c *Coord) UnmarshalText(p []byte) error {
    if n, err := fmt.Sscanf(string(p), &quot;%d,%d&quot;, &amp;c.X, &amp;c.Y); err != nil {
        return err
    } else if n != 2 {
        return errors.New(&quot;Cannot parse coord: &quot; + string(p))
    }
    return nil
}"><pre class="notranslate"><code class="notranslate">type Coord struct{ X, Y int }
func (c Coord) MarshalText() ([]byte, error) {
    return []byte(fmt.Sprintf("%d,%d", c.X, c.Y)), nil
}
func (c *Coord) UnmarshalText(p []byte) error {
    if n, err := fmt.Sscanf(string(p), "%d,%d", &amp;c.X, &amp;c.Y); err != nil {
        return err
    } else if n != 2 {
        return errors.New("Cannot parse coord: " + string(p))
    }
    return nil
}
</code></pre></div>
<p dir="auto">And the Go struct</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="map[Coord]bool{Coord{1, 2}: true, Coord{3, 4}: true}"><pre class="notranslate"><code class="notranslate">map[Coord]bool{Coord{1, 2}: true, Coord{3, 4}: true}
</code></pre></div>
<p dir="auto">would correspond to</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{&quot;1,2&quot;: true,&quot;3,4&quot;:true}"><pre class="notranslate"><code class="notranslate">{"1,2": true,"3,4":true}
</code></pre></div>
<h1 dir="auto">Considerations</h1>
<p dir="auto">If the struct marshals to a non-unique value, e.g.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="func (c Coord) MarshalText() ([]byte, error) {
    return []byte(&quot;always the same&quot;), nil
}"><pre class="notranslate"><code class="notranslate">func (c Coord) MarshalText() ([]byte, error) {
    return []byte("always the same"), nil
}
</code></pre></div>
<p dir="auto">The the json encoder would output JSON that has repeated keys, e.g.:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{&quot;always the same&quot;: true,&quot;always the same&quot;:true}"><pre class="notranslate"><code class="notranslate">{"always the same": true,"always the same":true}
</code></pre></div>
<p dir="auto">This is valid JSON.</p>
<p dir="auto">Similarly, when decoding a map, it would unmarshal each key and value and then assign that into the map, so last-write-wins, as is currently done.</p>
<p dir="auto">An interesting side effect is that it would then be possible to explicitly handle JSON with repeated keys (or even explicitly record the order of the json keys) by having the go-side map key TextUnmarshaler have non-deterministic unmarshaling (e.g. record timestamp for each unmarshal).</p>
<p dir="auto">by <strong>lexszero</strong>:</p>
<pre class="notranslate">What steps will reproduce the problem?
Build any package using cgo wtih following command:
GOARM=5 GOARCH=arm go build -x

What is the expected output?
Package build process

What do you see instead?
lexs@nyapad ~/.go/src/code.google.com/p/gosqlite/sqlite &gt; GOARM=5 GOARCH=arm go build
-x
WORK=/tmp/go-build982624259

and nothing more. return code is 0

Which compiler are you using (5g, 6g, 8g, gccgo)?
5g

Which operating system are you using?
linux/amd64

Which version are you using?  (run 'go version')
go version devel +1fcddf5fd778 Wed May 22 14:22:50 2013 -0700 linux/amd64

Please provide any additional information below.
Building packages that doesn't using cgo with command above works fine. Manual running
building commands analogous to those issued by 'GOARCH=amd64 go build -x' for the same
package (with replacing 6g to 5g, gcc to arm-none-linux-gnueabi-gcc, fixing cflags, etc)
also works fine, except for absent package 'runtime/cgo', which silently wasn't built
during go installation process for the same reason.</pre>