golang 使用接口进行从字符串到Struct的类型转换的基本示例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang 使用接口进行从字符串到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)

}

golang中接口interface和struct结构类的分析

再golang中,我们要充分理解interface和struct这两种数据类型。为此,我们需要优先理解type的作用。

type是golang语言中定义数据类型的唯一关键字。对于type中的匿名成员和指针成员,这里先不讲,重点讲解interface和struct这两种特殊的数据类型。

interface和struct也是数据类型,特殊在于interface作为万能的接口类型,而struct作为常用的自定义数据类型的关键字。说到这里相比大家已经明白interface的侧重点在于接口的定义(方法),而struct侧重点在于数据结构的定义。使用struct定义了数据结构,可以直接使用func方法定义数据结构中使用的方法。但是为了解耦,为了扩展,一般在真正设置功能性函数时,除了内置的数据类型外,都推荐使用接口的方法来传递相关方法。

既然推荐使用接口的方法来作为参数,那么具体结构中的数据成员又如何访问呢?golang提供了非常方便的类型查询和类型转换方法。名称.(type)用于类型查询,名称.(具体类型)用于类型转换。因此,使用接口作为函数参数是很有价值的。

另外,我们还需要明白对象和对象指针在golang中的微妙处理,golang可以自动将对数据类型定义的方法抓转换成对数据类型指针定义的方法。但不能自动的将对数据类型指针的方法转换为对数据类型定义的方法。

以下是我们的测试程序,注释已经注明了相关说明。

以下是执行结果

 

以上是关于golang 使用接口进行从字符串到Struct的类型转换的基本示例的主要内容,如果未能解决你的问题,请参考以下文章