命令记不住

登陆

类型断言

类型断言

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
}