golang interface{} Type assertions类型断言 x.(T) 和Type switches类型选择 switch x.(type) 的区别 与官方详解

在golang的开发中,我们经常会用到类型断言 type assertions 和 switch x.(type) 类型选择,他们都可以对interface{} 空接口类型的数据进行类型断言, 他们的功能类似但是有区别, 区别如下:

共同点: 都可以对interface{}  / any 类型的数据进行数据类型的断言

区别:  

类型断言 x.(T)   只能对 interface{}  / any 类型的数据进行数据类型的断言

switch x.(type)类型选择  可以对 interface{}  / any 类型数据进行选择, 也可以对接口类型数据进行类型选择(这个是他和类型断言x.(T) 的主要区别)

他们的详细用法和使用示例见golang白皮书详解, 为了保留原汁原味,直接贴官方英文了,单词也简单,应该都能看明白!

Type assertions类型断言官方详解

For an expression x of interface type, but not a type parameter, and a type T, the primary expression

x.(T)


asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

More precisely, if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T. In this case, T must implement the (interface) type of x; otherwise the type assertion is invalid since it is not possible for x to store a value of type T. If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.

If the type assertion holds, the value of the expression is the value stored in x and its type is T. If the type assertion is false, a run-time panic occurs. In other words, even though the dynamic type of x is known only at run time, the type of x.(T) is known to be T in a correct program.

var x interface{} = 7          // x has dynamic type int and value 7
i := x.(int)                   // i has type int and value 7

type I interface { m() }

func f(y I) {
    s := y.(string)        // illegal: string does not implement I (missing method m)
    r := y.(io.Reader)     // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
    …
}


A type assertion used in an assignment statement or initialization of the special form

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool


yields an additional untyped boolean value. The value of ok is true if the assertion holds. Otherwise it is false and the value of v is the zero value for type T. No run-time panic occurs in this case.

Type switches 类型选择官方详解

A type switch compares types rather than values. It is otherwise similar to an expression switch. It is marked by a special switch expression that has the form of a type assertion using the keyword type rather than an actual type:

switch x.(type) {
// cases
}


Cases then match actual types T against the dynamic type of the expression x. As with type assertions, x must be of interface type, but not a type parameter, and each non-interface type T listed in a case must implement the type of x. The types listed in the cases of a type switch must all be different.

TypeSwitchStmt  = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
TypeCaseClause  = TypeSwitchCase ":" StatementList .
TypeSwitchCase  = "case" TypeList | "default" .


The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the end of the TypeSwitchCase in the implicit block of each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.

Instead of a type, a case may use the predeclared identifier nil; that case is selected when the expression in the TypeSwitchGuard is a nil interface value. There may be at most one nil case.

Given an expression x of type interface{}, the following type switch:

switch i := x.(type) {
case nil:
    printString("x is nil")                // type of i is type of x (interface{})
case int:
    printInt(i)                            // type of i is int
case float64:
    printFloat64(i)                        // type of i is float64
case func(int) float64:
    printFunction(i)                       // type of i is func(int) float64
case bool, string:
    printString("type is bool or string")  // type of i is type of x (interface{})
default:
    printString("don't know the type")     // type of i is type of x (interface{})
}


could be rewritten:

v := x  // x is evaluated exactly once
if v == nil {
    i := v                                 // type of i is type of x (interface{})
    printString("x is nil")
} else if i, isInt := v.(int); isInt {
    printInt(i)                            // type of i is int
} else if i, isFloat64 := v.(float64); isFloat64 {
    printFloat64(i)                        // type of i is float64
} else if i, isFunc := v.(func(int) float64); isFunc {
    printFunction(i)                       // type of i is func(int) float64
} else {
    _, isBool := v.(bool)
    _, isString := v.(string)
    if isBool || isString {
        i := v                         // type of i is type of x (interface{})
        printString("type is bool or string")
    } else {
        i := v                         // type of i is type of x (interface{})
        printString("don't know the type")
    }
}


A type parameter or a generic type may be used as a type in a case. If upon instantiation that type turns out to duplicate another entry in the switch, the first matching case is chosen.

func f[P any](x any) int {
    switch x.(type) {
    case P:
        return 0
    case string:
        return 1
    case []P:
        return 2
    case []byte:
        return 3
    default:
        return 4
    }
}

var v1 = f[string]("foo")   // v1 == 0
var v2 = f[byte]([]byte{})  // v2 == 2


The type switch guard may be preceded by a simple statement, which executes before the guard is evaluated.

The "fallthrough" statement is not permitted in a type switch.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值