Go 要求在不同类型之间进行显式转换。
类型之间的转换(也叫类型强制转换)通过一个以目标类型名为名称的函数来完成。
例如,要把 int 转换成 float64,需要这样做:
var x int = 42 // x has type int
f := float64(x) // f has type float64 (ie. 42.0)
strconv 包可以在基本类型(如 int)和 string 之间进行转换。
import "strconv"
var intString string = "42"
var i, err = strconv.Atoi(intString)
var number int = 12
var s string = strconv.Itoa(number)
Go 中的接口可能会让底层类型变得不明确。
类型断言让我们可以用这样的语法提取接口值底层的具体值:interfaceVariable.(concreteType)。
例如:
var input any = 12
number := input.(int)
注意:如果接口变量持有的值不是该具体类型,就会引发 panic。
利用类型断言的两个返回值,我们可以判断接口值是否持有某个具体类型:一个是底层的值,另一个是表示断言是否成功的布尔值。 例如:
str, ok := input.(string) // no panic if input is not a string
如果 input 持有的是 string,那么 str 就是底层的值,ok 为 true。
如果 input 持有的不是 string,那么 str 就是 string 类型的零值(即 "",空字符串),ok 为 false。
无论哪种情况都不会发生 panic。
类型分支可以依次执行多个类型断言。
它的语法和类型断言相同(interfaceVariable.(concreteType)),只是把 concreteType 换成了关键字 type。
下面是一个例子:
var i any = 12 // try: 12.3, true, int64(12), []int{}, map[string]int{}
switch v := i.(type) {
case int:
fmt.Printf("the integer %d\n", v)
case string:
fmt.Printf("the string %s\n", v)
default:
fmt.Printf("type, %T, not handled explicitly: %#v\n", v, v)
}
珍在一家大型工厂的分拣室工作。 分拣室需要处理送进来的一切东西,给它们贴上标签分类。 珍负责那些被预先归类为数字的东西,她需要一个程序来帮她分拣。
大多数基本值都应该得到简单直接的标签。
对于数字,她想要"This is the number 2.0"这样的字符串(如果这个数字是 2)。
无论是整数还是浮点数,珍都想要同样的输出。
有几个Box接口,需要拆开它们才能取出里面的内容。
对于NumberBox,她想要"This is a box containing the number 3.0"这样的字符串(如果Number()方法返回 3)。
对于FancyNumberBox,她想要"This is a fancy box containing the number 4.0"这样的字符串,但只有当它的类型是FancyNumber时才可以。
任何意料之外的东西都应该返回"Return to sender",这样珍就能把它们退回到原来的地方。
珍希望数字返回像"This is the number 2.0"这样的字符串(小数点后保留一位):
fmt.Println(DescribeNumber(-12.345))
// Output: This is the number -12.3
珍希望数字盒子返回像"This is a box containing the number 2.0"这样的字符串(同样,小数点后保留一位):
fmt.Println(DescribeNumberBox(numberBoxContaining{12}))
// Output: This is a box containing the number 12.0
珍需要一个辅助函数,从FancyNumberBox中提取数字。
如果FancyNumberBox是FancyNumber,就提取它的值,并把string转换成int。
其他任何类型的FancyNumberBox都应该返回 0。
fmt.Println(ExtractFancyNumber(FancyNumber{"10"}))
// Output: 10
fmt.Println(ExtractFancyNumber(AnotherFancyNumber{"4"}))
// Output: 0
如果FancyNumberBox是FancyNumber,珍想要"This is a fancy box containing the number 4.0"这样的字符串。
其他任何类型的FancyNumberBox都应该返回"This is a fancy box containing the number 0.0"。
fmt.Println(DescribeFancyNumberBox(FancyNumber{"10"}))
// Output: This is a fancy box containing the number 10.0
fmt.Println(DescribeFancyNumberBox(AnotherFancyNumber{"4"}))
// Output: This is a fancy box containing the number 0.0
注意:我们应该使用ExtractFancyNumber函数!
DescribeAnything
这是珍需要的主函数,它接受任意输入。
DescribeAnything应该根据传入值的类型,把工作委托给其他函数。
具体来说:
int和float64都应该委托给DescribeNumber
NumberBox应该委托给DescribeNumberBox
FancyNumberBox应该委托给DescribeFancyNumberBox
"Return to sender"
fmt.Println(DescribeAnything(numberBoxContaining{12.345}))
// Output: This is a box containing the number 12.3
fmt.Println(DescribeAnything("some string"))
// Output: Return to sender