Description
What version of Go are you using (go version
)?
$ go version go version go1.12.9 darwin/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GOARCH="amd64" GOBIN="" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOOS="darwin" GOPROXY="" GORACE="" GOROOT="/usr/local/Cellar/go/1.12.9/libexec" GOTMPDIR="" GOTOOLDIR="/usr/local/Cellar/go/1.12.9/libexec/pkg/tool/darwin_amd64" GCCGO="gccgo" CC="clang" CXX="clang++" 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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/gg/29c0x6691455vgkxwl2hrpgc0000gn/T/go-build354245371=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
The Go source code
package gocode
import "fmt"
type Bytes struct {
elements []byte
}
func NewBytes(elements []byte) *Bytes {
fmt.Println("Constructor: ", elements)
return &Bytes{elements: elements}
}
func (bytes *Bytes) GetElements() []byte {
fmt.Println("Getter: ", bytes.elements)
return bytes.elements
}
is compiled into an iOS framework using $GOPATH/bin/gomobile bind -target ios -o Gocode.framework gocode
.
In a minimal iOS application there is the Swift code
import Foundation
import Gocode
let data = Data(repeating: 0, count: 8)
print("Data: \([UInt8](data))")
let bytes = GocodeNewBytes(data)!
print("Elements: \([UInt8](bytes.getElements()!))")
print("Data: \([UInt8](data))")
which can be compiled and run just fine. However, the printed values are not what I would expect.
What did you expect to see?
Data: [0, 0, 0, 0, 0, 0, 0, 0]
Constructor: [0 0 0 0 0 0 0 0]
Getter: [0 0 0 0 0 0 0 0]
Elements: [0, 0, 0, 0, 0, 0, 0, 0]
Data: [0, 0, 0, 0, 0, 0, 0, 0]
What did you see instead?
Data: [0, 0, 0, 0, 0, 0, 0, 0]
Constructor: [0 0 0 0 0 0 0 0]
Getter: [184 144 247 1 1 0 0 0]
Elements: [184, 144, 247, 1, 1, 0, 0, 0]
Data: [0, 0, 0, 0, 0, 0, 0, 0]
The data is correctly passed to the Go functions and back to Swift, but internally constructing the Bytes
object it somehow changes. If I rewrite the constructor in Go as
func NewBytes(elements []byte) *Bytes {
fmt.Println("Constructor: ", elements)
tmp := make([]byte, len(elements))
copy(tmp, elements)
return &Bytes{elements: tmp}
}
it works as anticipated. I'm not sure whether this is a bug or expected but unpleasant behavior due to Go's and Swift's handling of values and references. If the latter is true I really have no idea how to solve this issue on the Swift side in order to utilize Go libraries using []byte
at any interface function.