dbohdan 2016-09-19: The following is, to my best knowledge, about as simple as a 
Tcl extension written in 
Go can get. The wrapper functions 
*_cgo are necessary since you 
can't pass a pointer to a Go function
 to C code. In a real extension those wrappers could be generated automatically via 
go generate
 and a Tcl script.
The code has been tested with Go v1.6.3 on Linux x86_64. To build it yourself save 
example.go, 
wrappers.go and 
Makefile in the same directory, replace the spaces with tabs with
$ sed 's/        /\t/g' -i example.go wrappers.go Makefile
which is necessary for the 
Makefile to work, then run 
make test.
 Makefile  edit
libtclgoexample.so: example.go wrappers.go
        go build -o $@ -buildmode=c-shared example.go wrappers.go
test: libtclgoexample.so
        echo 'load libtclgoexample.so; puts [hello]; puts [square 5]' | tclsh
.PHONY: test example.go  edit
//example.go v0.2.0
package main
/*
#include <stdlib.h>
#include <tcl.h>
#include <tclDecls.h>
#cgo LDFLAGS: -ltcl8.6
int Hello_Cmd_cgo(ClientData cdata, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]);
int Square_Cmd_cgo(ClientData cdata, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]);
*/
import "C"
import (
        "reflect"
        "unsafe"
)
const (
        TCL_OK       = 0
        TCL_ERROR    = 1
        TCL_RETURN   = 2
        TCL_BREAK    = 3
        TCL_CONTINUE = 4
)
func (interp *C.struct_Tcl_Interp) createCommand(name string,
        f *C.Tcl_ObjCmdProc) {
        cName := C.CString(name)
        defer C.free(unsafe.Pointer(cName))
        C.Tcl_CreateObjCommand(interp, cName, f, nil, nil)
}
func (interp *C.struct_Tcl_Interp) wrongNumArgs(objc C.int,
        objv **C.Tcl_Obj, message string) {
        var cMessage *C.char
        if message == "" {
                cMessage = nil
        } else {
                cMessage = C.CString(message)
                defer C.free(unsafe.Pointer(cMessage))
        }
        C.Tcl_WrongNumArgs(interp, objc, objv, cMessage)
}
func slicify(objc C.int, objv **C.Tcl_Obj) (objs []*C.Tcl_Obj) {
        // http://stackoverflow.com/a/14828189
        sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&objs))
        sliceHeader.Cap = (int)(objc)
        sliceHeader.Len = (int)(objc)
        sliceHeader.Data = uintptr(unsafe.Pointer(objv))
        return
}
//export Hello_Cmd
func Hello_Cmd(cdata C.ClientData, interp *C.struct_Tcl_Interp,
        objc C.int, objv **C.Tcl_Obj) C.int {
        if objc != 1 {
                interp.wrongNumArgs(1, objv, "")
                return TCL_ERROR
        }
        result := C.CString("Hello, World!")
        defer C.free(unsafe.Pointer(result))
        C.Tcl_SetObjResult(interp, C.Tcl_NewStringObj(result, -1))
        return TCL_OK
}
//export Square_Cmd
func Square_Cmd(cdata C.ClientData, interp *C.struct_Tcl_Interp,
        objc C.int, objv **C.Tcl_Obj) C.int {
        if objc != 2 {
                interp.wrongNumArgs(1, objv, "value")
                return TCL_ERROR
        }
        objs := slicify(objc, objv)
        var i C.int
        if C.Tcl_GetIntFromObj(interp, objs[1], &i) != TCL_OK {
                return TCL_ERROR
        }
        C.Tcl_SetObjResult(interp, C.Tcl_NewIntObj((C.int)(i*i)))
        return TCL_OK
}
//export Tclgoexample_Init
func Tclgoexample_Init(interp *C.struct_Tcl_Interp) C.int {
        interp.createCommand("::hello", (*C.Tcl_ObjCmdProc)(C.Hello_Cmd_cgo))
        interp.createCommand("::square", (*C.Tcl_ObjCmdProc)(C.Square_Cmd_cgo))
        return TCL_OK
}
func main() {} wrappers.go  edit
//wrappers.go
package main
/*
#include <tcl.h>
#include <tclDecls.h>
int Hello_Cmd_cgo(ClientData cdata, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]) {
        int Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc,
                Tcl_Obj *const objv[]);
        return Hello_Cmd(cdata, interp, objc, objv);
}
int Square_Cmd_cgo(ClientData cdata, Tcl_Interp *interp, int objc,
        Tcl_Obj *const objv[]) {
        int Square_Cmd(ClientData cdata, Tcl_Interp *interp, int objc,
                Tcl_Obj *const objv[]);
        return Square_Cmd(cdata, interp, objc, objv);
}
*/
import "C"