英文:
What does the keyword type mean when used in a switch?
问题
我在golang中看到了几个这样的代码实例:
func process(node ast.Node) Foo {
switch n := node.(type) {
// ... 省略部分代码
}
}
ast.Node
是一个接口。node.(type)
这段代码是用来进行反射的吗?是为了找出接口的实际实现者吗?
英文:
I have seen several instances of this code in golang:
func process(node ast.Node) Foo {
switch n := node.(type) {
// ... removed for brevity
}
}
ast.Node
is an interface. Is the node.(type)
snippet code to perform reflection; to find out the actual implementers of the interface ?
答案1
得分: 11
是的,这被称为类型开关(Type switch)。它允许你根据传递的接口的实际类型执行代码。
我认为官方文档中的示例很清楚:
开关语句也可以用于发现接口变量的动态类型。这种类型开关使用带有关键字type的类型断言语法。如果开关语句在表达式中声明了一个变量,那么该变量在每个分支中将具有相应的类型。在这种情况下,重用该名称是惯用的做法,实际上在每种情况下声明了一个具有相同名称但不同类型的新变量。
var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T 打印 t 的类型
case bool:
fmt.Printf("boolean %t\n", t) // t 的类型是 bool
case int:
fmt.Printf("integer %d\n", t) // t 的类型是 int
case *bool:
fmt.Printf("pointer to boolean %t\n", *t) // t 的类型是 *bool
case *int:
fmt.Printf("pointer to integer %d\n", *t) // t 的类型是 *int
}
在一个类型正确的程序中,你不应该经常使用这个,但在需要时它很方便。一个使用示例:假设你实现了一个数据库驱动程序,你可能需要根据 Go 变量的类型进行转换。这是go-sql/mysql 驱动程序的一个摘录:
// Scan 实现了 Scanner 接口。
// 值的类型必须是 time.Time 或 string / []byte(格式化的时间字符串),
// 否则 Scan 将失败。
func (nt *NullTime) Scan(value interface{}) (err error) {
if value == nil {
nt.Time, nt.Valid = time.Time{}, false
return
}
switch v := value.(type) {
case time.Time:
nt.Time, nt.Valid = v, true
return
case []byte:
nt.Time, err = parseDateTime(string(v), time.UTC)
nt.Valid = (err == nil)
return
case string:
nt.Time, err = parseDateTime(v, time.UTC)
nt.Valid = (err == nil)
return
}
nt.Valid = false
return fmt.Errorf("Can't convert %T to time.Time", value)
}
英文:
Yes. It's called a Type switch. It allows you to execute code depending on the actual type of the interface you pass.
I think the official documentation, with its example, is clear :
> A switch can also be used to discover the dynamic type of an interface
> variable. Such a type switch uses the syntax of a type assertion with
> the keyword type inside the parentheses. If the switch declares a
> variable in the expression, the variable will have the corresponding
> type in each clause. It's also idiomatic to reuse the name in such
> cases, in effect declaring a new variable with the same name but a
> different type in each case.
var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T prints whatever type t has
case bool:
fmt.Printf("boolean %t\n", t) // t has type bool
case int:
fmt.Printf("integer %d\n", t) // t has type int
case *bool:
fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}
You should not use that too often in a properly typed program but it's convenient when you need it. An example of use : Suppose you implement a database driver, you may have to do conversions depending on the type of the Go variables. Here's an extract of the go-sql/mysql driver :
// Scan implements the Scanner interface.
// The value type must be time.Time or string / []byte (formatted time-string),
// otherwise Scan fails.
func (nt *NullTime) Scan(value interface{}) (err error) {
if value == nil {
nt.Time, nt.Valid = time.Time{}, false
return
}
switch v := value.(type) {
case time.Time:
nt.Time, nt.Valid = v, true
return
case []byte:
nt.Time, err = parseDateTime(string(v), time.UTC)
nt.Valid = (err == nil)
return
case string:
nt.Time, err = parseDateTime(v, time.UTC)
nt.Valid = (err == nil)
return
}
nt.Valid = false
return fmt.Errorf("Can't convert %T to time.Time", value)
}
答案2
得分: 2
它是**类型开关**:
> 开关还可以用于发现接口变量的动态类型。这种类型开关使用类型断言的语法,括号内使用关键字type。如果开关在表达式中声明一个变量,那么每个分支中的变量将具有相应的类型。在这种情况下,重用变量名是惯用的做法,实际上在每种情况下声明一个具有相同名称但不同类型的新变量。
使用类型开关,您可以根据接口值的类型进行开关(仅限接口值):
func do(v interface{}) string {
switch u := v.(type) {
case int:
return strconv.Itoa(u*2) // u 的类型为 int
case string:
mid := len(u) / 2 // 分割 - u 的类型为 string
return u[mid:] + u[:mid] // 拼接
}
return "unknown"
}
do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"
英文:
It is TYPE SWITCH:
> A switch can also be used to discover the dynamic type of an interface
> variable. Such a type switch uses the syntax of a type assertion with
> the keyword type inside the parentheses. If the switch declares a
> variable in the expression, the variable will have the corresponding
> type in each clause. It's also idiomatic to reuse the name in such
> cases, in effect declaring a new variable with the same name but a
> different type in each case.
With a type switch you can switch on the type of an interface value (only):
func do(v interface{}) string {
switch u := v.(type) {
case int:
return strconv.Itoa(u*2) // u has type int
case string:
mid := len(u) / 2 // split - u has type string
return u[mid:] + u[:mid] // join
}
return "unknown"
}
do(21) == "42"
do("bitrab") == "rabbit"
do(3.142) == "unknown"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论