
类型断言
1.类型断言定义
类型断言会检查作为操作数的动态类型是否满足指定的断言类型
类型断言是一个作用在接口值上的操作,写出来类似
x.(T),其中x是一个接口类型的表达式,而T是一个类型,称为断言类型类型断言就是用来从它的操作数中把具体类型的值提取出来的操作
类型断言是一个接口值表达式,从一个接口类型变为拥有另一套方法的接口类型,但保留了接口值中的动态类型和动态值部分
var w io.Writer w = os.Stdout rw := w.(io.ReadWriter)无论哪种类型作为断言类型,如果操作数是一个空接口值,类型断言都失败
2.使用断言类型来识别错误
使用专门的类型来表示结构化的错误值
例如os包定义了一个PathError类型来表示在与一个文件路径相关的操作上发生错误,一个类似的LInkError用来表述在与两个文件路径相关的操作上发生错误
//记录了错误以及相关的操作和文件路径 type PathError struct { Op string Path string Err error } func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }错误识别通常必须在失败操作发生时马上处理,而不是等到错误消息返回给调用者之后
3.通过接口类型断言来查询特性
如果x满足这两种接口中的一个,就直接确定格式化方法,如果不满足,默认处理部分大致会使用反射来处理所有其他类型
func formatOneValue(x interface{}) string { if err, ok := x.(error); ok { return err.Error() } if str, ok := x.(Stringer); ok { return str.String() } }
4.类型分支
一个switch语句可以把包含一长串相等比较的if-else语句简化掉,一个相似的类型分支(type switch)语句则可以用来简化一长串的类型断言if-else语句
类型分支的最简单形式与普通分支语句类似,两个的差别是操作数改为x.(type),注意这里直接写关键词type,而不是一个特定类型
switch x.(type){ case nil: case int,uint; case bool: case string: default: }每个单一类型的分支块内,变量x的类型都与该分支的类型一致
func sqlQuote(x interface{}) string { switch x := x.(type) { case nil: return "NULL" case int, uint: return fmt.Sprintf("%d", x) case bool: if x { return "TURE" } return "FALSE" case string: return sqlQuoteString(x) //未显示代码 default: panic(fmt.Sprintf("unexpected type %T: %v", x, x)) } }
5.常见类型断言示例
- 类型断言(一)
package main import "fmt" type people struct { Name string } func main(){ var i interface{} = &people{"墨持"} //类型断言 if v,ok := i.(*people);ok{ fmt.Print(v.Name) }else{ fmt.Println("类型匹配失败") } } C:\Users\vSphere\go\src\day04>go run 05.go 墨持
- 类型断言(二)
package main import ( "fmt" ) type people struct { Name string } func main(){ var i interface{} = people{"乘志"} switch i.(type) { case people: fmt.Println("people") case *people: fmt.Println("*people") default: fmt.Println("类型匹配失败") } } C:\Users\vSphere\go\src\day04>go run 05.go people基于标记的XML解析
func main() { dec := xml.NewDecoder(os.Stdin) var stack []string // stack of element names for { tok, err := dec.Token() if err == io.EOF { break } else if err != nil { fmt.Fprintf(os.Stderr, "xmlselect: %v\n", err) os.Exit(1) } switch tok := tok.(type) { case xml.StartElement: stack = append(stack, tok.Name.Local) // push case xml.EndElement: stack = stack[:len(stack)-1] // pop case xml.CharData: if containsAll(stack, os.Args[1:]) { fmt.Printf("%s: %s\n", strings.Join(stack, " "), tok) } } } } // containsAll reports whether x contains the elements of y, in order. func containsAll(x, y []string) bool { for len(y) <= len(x) { if len(y) == 0 { return true } if x[0] == y[0] { y = y[1:] } x = x[1:] } return false }