Basic Example of using Interfaces for type conversion from strings to Struct
// nativecmdr project nativecmdr.go
package main
import (
"bytes"
"fmt"
"log"
"os/exec"
"strconv"
"strings"
"syscall"
)
const (
ENOSLC = "failed to produce slice of values"
ENOMATRIX = "there are no x,y elements in matrix"
PYCMD = "/usr/local/bin/python"
PYARG_WORK = "for i in range(0, 16): print('%d,%d' % (i, i*i))"
PYARG_NO_WORK = "for i in range(0, 16): print('%d:%d' % (i, i*i))"
)
type Nativer interface {
NativeType(s string) error
HasError() bool
}
type MatrixArrayResult struct {
Xprime []int
Yprime []int
Error error
ExitCode int
}
type CmdResult struct {
Stdout string
Stderr string
ExitCode int
}
func (m *MatrixArrayResult) HasError() bool {
if m.ExitCode == 0 {
return false
} else {
return true
}
}
func (m *MatrixArrayResult) NativeType(s string) error {
var mkerr = func(s string) error {
return fmt.Errorf("%v", s)
}
var strslc = strings.Split(s, "\n")
if len(strslc) < 1 {
m.Error = mkerr(ENOSLC)
return mkerr(ENOSLC)
}
for _, val := range strslc {
tm := strings.Split(val, ",")
if len(tm) < 2 { // range errors are not what we want
break
}
x, _ := strconv.Atoi(tm[0]) // Unchecked err
y, _ := strconv.Atoi(tm[1]) // Unchecked err
m.Xprime = append(m.Xprime, x)
m.Yprime = append(m.Yprime, y)
}
if len(m.Xprime) < 1 || len(m.Yprime) < 1 {
m.Error = mkerr(ENOMATRIX)
return mkerr(ENOMATRIX)
}
return nil
}
func ErrHandle(e error) error {
if e != nil {
log.Printf("%v", fmt.Errorf("%v", e.Error()))
return e
}
return nil
}
func RunCmd(ex Nativer, command string, args ...string) error {
var result CmdResult
cmd := exec.Command(command, args...)
// Stdout buffer
cmdOutput := &bytes.Buffer{}
// Attach buffer to command
cmd.Stdout = cmdOutput
//Stderr buffer
cmdError := &bytes.Buffer{}
//Attach buffer to cmd
cmd.Stderr = cmdError
var waitStatus syscall.WaitStatus
if err := cmd.Run(); err != nil {
//Grab stderr
result.Stderr = string(cmdError.Bytes())
// Did the command fail because of an unsuccessful exit code
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus = exitError.Sys().(syscall.WaitStatus)
//Store exit code
result.ExitCode = waitStatus.ExitStatus()
} else {
//There was not exit error because the command never ran.
//Let's set an error ourselves so there is no confusion.
result.Stderr = fmt.Sprintf("error running command: %s", command)
//Store exit code for Bash command not found
result.ExitCode = 127
}
} else {
//Grab stdout and stuff it into return stdout as string
result.Stdout = string(cmdOutput.Bytes())
// Command was successful
waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
//Store exit code
result.ExitCode = waitStatus.ExitStatus()
}
if e := ex.NativeType(result.Stdout); e != nil {
return nil // In reality this should return `e` instead of nil
}
return nil
}
func main() {
var Amatrix Nativer = &MatrixArrayResult{}
var Bmatrix Nativer = &MatrixArrayResult{}
//var Amatrix = Nativer(&MatrixArrayResult{}) // A bit more ugly than above
//var Bmatrix = Nativer(&MatrixArrayResult{})
// This should work, Nil error
if e := RunCmd(Amatrix, PYCMD, "-c", PYARG_WORK); e == nil {
fmt.Printf("Matrix Xs: %v\nMatrix Ys: %v\nError: %v\n",
Amatrix.(*MatrixArrayResult).Xprime, // assertions must be checked
Amatrix.(*MatrixArrayResult).Yprime,
Amatrix.(*MatrixArrayResult).Error)
}
// This should not work, non-Nil error
if e := RunCmd(Bmatrix, PYCMD, "-c", PYARG_NO_WORK); e == nil {
fmt.Printf("Matrix Xs: %v\nMatrix Ys: %v\nError: %v\n",
Bmatrix.(*MatrixArrayResult).Xprime, // assertions must be checked
Bmatrix.(*MatrixArrayResult).Yprime,
Bmatrix.(*MatrixArrayResult).Error)
}
//
// Results of running above should look something like this:
//
//Matrix Xs: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
//Matrix Ys: [0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225]
//Error: <nil>
//Matrix Xs: []
//Matrix Ys: []
//Error: there are no x,y elements in matrix
}
// mknativetype project main.go
package main
import (
"fmt"
"strconv"
"strings"
)
type Nativer interface {
NativeType(s string) error
}
type Foo struct {
Fruit string
Veg string
Array []byte
}
type Bar struct {
First string
Last string
Array []byte
}
type Matrix struct {
X int
Y int
}
func (m *Matrix) NativeType(s string) error {
var sep = ","
var strslc = strings.SplitN(s, sep, 4)
m.X, _ = strconv.Atoi(strslc[0])
m.Y, _ = strconv.Atoi(strslc[2])
return nil
}
func (f *Foo) NativeType(s string) error {
var sep = ";"
var strslc = strings.SplitN(s, sep, 3)
f.Fruit = strslc[0]
f.Veg = strslc[1]
f.Array = []byte(s)
return nil
}
func (b *Bar) NativeType(s string) error {
var sep = " "
var strslc = strings.SplitN(s, sep, 5)
b.First = strslc[2]
b.Last = strslc[3]
b.Array = []byte(fmt.Sprintf("%s %s", strslc[2], strslc[3]))
return nil
}
func MimicCommand(s string, n Nativer) error {
err := n.NativeType(s)
if err != nil {
return fmt.Errorf("%s", "poof")
}
return nil
}
func main() {
var f1 Nativer = &Foo{}
var b1 Nativer = &Bar{}
var m1 Nativer = &Matrix{}
MimicCommand("apple;detroit-red beet;banana;sweet potato", f1)
MimicCommand("junk more.junk Joe Buckeye is a Ducks Fan", b1)
MimicCommand("100,-0.5,20,-0.3", m1)
fmt.Printf("Food -- Fruit: %v Vegetable: %v Array: %v\n", f1.(*Foo).Fruit, f1.(*Foo).Veg, f1.(*Foo).Array)
fmt.Printf("Name -- First: %v Last: %v Array: %v\n", b1.(*Bar).First, b1.(*Bar).Last, b1.(*Bar).Array)
fmt.Printf("Matrix -- X: %v Y: %v\n", m1.(*Matrix).X, m1.(*Matrix).Y)
}