golang 使用接口进行从字符串到Struct的类型转换的基本示例 Posted 2021-05-24
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可以自动将对数据类型定义的方法抓转换成对数据类型指针定义的方法。但不能自动的将对数据类型指针的方法转换为对数据类型定义的方法。
以下是我们的测试程序,注释已经注明了相关说明。
package main
import " fmt "
//定义一个接口
type Stryc interface {
Int() int
}
//定义一个自定义数据类型
type myCls struct {
value int
}
//使用数据类型指针绑定方法(在调用方法时,数据类型在golang中会默认转换为数据类型指针进行使用)
func(a * myCls) Int() int{
return a.value
}
//定义一个函数,参数为一个自定义的数据类型
func printTheValueByStruct(arg myCls){
fmt.Printf( " the value is %d \n " ,arg.Int())
}
//定义一个函数,参数为一个接口
func printTheValue(arg Stryc) int{
fmt.Printf( " the value is %d \n " ,arg.Int()/*使用接口调用接口的方法*/)
return arg.Int()
}
//定义一个函数,参数为动态个数的接口类型参数
func printAnyValue(args ...interface{}){
//使用for range方法获取每一个接口
for _,arg := range args{
//使用.(type)方法查询接口的数据类型
switch arg.(type) {
case int:
fmt.Println( " the type is int " )
case string:
fmt.Println( " the type is string " )
case myCls: /*是自定义数据类型*/
//使用.(数据类型)进行强转
var b myCls = arg.(myCls)
fmt.Println( " the type is myCls, the function value is " , b.Int()/*d调用数据类型的方法,golang会转换为数据指针类型调用*/," the struct value is " , b.value/*调用数据结构的数据*/)
case Stryc: /*是定义的接口数据类型*/
fmt.Println( " the type is Stryc interface, the function value is " , arg.(Stryc).Int()/*将接口强转到指定接口,并调用方法*/)
}
}
}
func main(){
var V1 *myCls = new(myCls) //创建一个对象指针
V1.value = 1111111 //给对象赋值
var V2 myCls = myCls{222222222} //创建一个对象,给对象赋值
var a interface {} =myCls{33333} //创建一个对象,将对象赋值后传给一个万能类型接口
var a1 interface{} =&myCls{444444}//创建一个对象,将对象指针传给一个万能类型接口
fmt.Println( " hello world! " )
printTheValue(V1) //V1会转换为Stryc接口被调用其中的方法
printTheValue(a1.(Stryc)) //万能接口a1中放置的对象指针被强制转为Stryc接口调用
printTheValueByStruct( *V1) //强制将V1的对象使用*显示传入函数,因为参数是对象
printTheValueByStruct(a.(myCls)) //强制将万能接口a中放置的对象转换为对象传入函数,因为参数是对象
printTheValue( &V2) //将对象的指针传入函数,golang将其转换为Stryc接口
printAnyValue(V1 /*传入一个指针,会同Stryc接口数据类型匹配*/,
V2 /*传入一个对象,会同myCls数据类型匹配*/,
*V1/*将指针显示为对象传入,会同myCls数据类型匹配*/,
&V2/*将对象的指针传入,会同Stryc接口数据类型匹配*/)
}
以下是执行结果
hello world!
the value is 1111111
the value is 444444
the value is 1111111
the value is 33333
the value is 222222222
the type is Stryc interface , the function value is 1111111
the type is myCls, the function value is 222222222 the struct value is 222222222
the type is myCls, the function value is 1111111 the struct value is 1111111
the type is Stryc interface , the function value is 222222222
以上是关于golang 使用接口进行从字符串到Struct的类型转换的基本示例的主要内容,如果未能解决你的问题,请参考以下文章
golang 自定义接口体(与其他语言对象类似)
Golang中Struct与DB中表字段通过反射自动映射 - sqlmapper
golang反射
Golang interface 接口详解
Golang interface 接口详解
golang结构体组合与“多态” 2021-08-06