意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

021-类型(Type),类型转换和测试

来源:恒创科技 编辑:恒创科技编辑部
2024-01-26 04:46:59


go 是强类型的语言。

从一开始我们就知道 go 中定义变量是需要指定其类型的,就算是自动推导,那也是需要有类型的,只不过编译器帮你分析了其类型而已。


021-类型(Type),类型转换和测试

类型的作用是为了描述 object 相关的特性。比如它规定了 object 占用几个字节,在内存中是怎样的结构,是否支持一些操作符。

比如 go 的内置类型 ​​int32​​​,它表示整数,在内存中占用 4 个字节(32bit),它支持 ​​+, -, *, /​​​ 运算。在现实生活中,有很多东西可以使用 ​​int32​​ 来表示,比如 5 个人,20 岁,50 秒。

1. type

尽管 20 岁,50 秒的单位不同,但是他们都可以使用 ​​int32​​ 来描述。有时候,我们需要刻意区分不同单位的数字。比如我们不能用 50秒−20岁 50 秒 − 20 岁 ,这完全没有意义。

go 提供了关键字 type,允许我们根据已有的类型创建新类型。它的语法是如下:

type name underlying-type

我们将 underlying-type 称为 name 的底层类型。

比如:

type Second int32
type Year int32

它的语法非常像 c/c++ 里的 ​​typedef​​​,但是 ​​typedef​​​ 的含义是给类型定义新别名。在 go 里,type 关键字不仅仅是给类型定义新别名,而且它添加了更多的特性。比如上面的两种类型 ​​Second​​​ 和 ​​Year​​​,它们之间是不允许直接相互赋值,也不允许互相参与运算。尽管他们都是 ​​int32​​​ 的别名类型(以后我们应该说,他们的底层类型都是 ​​int32​​)。

go 刻意区分它们的目的是防止你无意犯错,将不同类型的值互相运算。

2. 类型转换

再举个例子,我们定义两个类型,一个是 ​​Second​​​,另一个是 ​​Minute​​.

type Second int32 // 秒
type Minute int32 // 分

很显然,​​Second​​​ 和 ​​Minute​​ 是不能直接相互运算的。但是它们之间是可以相互转换的。比如 1 分钟可以换算成 60 秒。

var s Second
var m Minute = 1
s = 60 * m // not ok

在 c/c++ 里,上面是 ok 的,但是在 go 里不行。虽然你给 ​​m​​​ 乘以了 60,但是运算结果仍然是 ​​Minute​​ 类型。go 采用的方案是使用显式类型转换:

var s Second
var m Minute = 1
s = Second(60

在 go 里,类型转换的语法就是 ​​T(x)​​​,T 表示什么任意类型。比如 ​​int32(x)​​​, ​​(*float64)(x)​​ 这些都是类型转换。不是所有的类型转换都能成功,go 类型转换需要满足下面的条件之一:

底层类型相同可以转换(这种转换只改变类型,不影响值)数值类型之间可以转换(这种转换会改变类型,如果底层类型不同,也可能影响值。比如 float64 转换成 int32 会丢失精度)字符串和一些 slice 类型(比如​​[]byte​​)之间可以转换。

另外,类型转换只发生在编译阶段。这意味着如果编译通过,运行时绝对可以转换成功。

3. 示例

这个例子来自 gopl,主要是摄氏温度(Celsius)和华氏温度(Fahrenheit)的互转。代码路径是 ​​gopl/programstructure/type/tempconv​

另外,这个例子还演示了 go 如何运行测试用例。

3.1 源码
// conv.go
package tempconv

type Celsius float64
type Fahrenheit float64

const (
AbsoluteZeroC Celsius = -273.15
FreezingC Celsius = 0
Boiling Celsius = 100
)

func CToF(c Celsius) Fahrenheit {
f := c*9/5 + 32
return Fahrenheit(f)
}

func FToC(f Fahrenheit) Celsius {
c := (f - 32) * 5 / 9
return

另外,还有一个测试文件 ​​conv_test.go​​.

package tempconv

import "fmt"

func ExampleOne() {
c := FToC(32)
fmt.Printf("32F = %.2fC\n", c)
// Output:
// 32F = 0.00C
}

func ExampleTwo() {
c := CToF(5)
fmt.Printf("5C = %.2fF\n", c)
// Output:
// 5C = 41.00F

运行结果:


021-类型(Type),类型转换和测试_go


图1 运行结果


3.2 测试

go 另一个强大的功能是天然对测试的支持。

这里我们先简单使用测试的一个功能——运行『示例函数』。就像 3.1 节中 conv_test.go 里的那两个函数。

有一些规则是必须的:

测试文件名必须以​​_test.go​​ 结尾。测试程序和被测试程序在同一个包里。示例函数名必须以 Example 开头。示例函数必须包含注释​​// Output:​​​ 才会运行(写成​​// output:​​ 也可以,但是冒号不能丢)​​// Output:​​ 后面必须要将输出结果写出来

满足了上面的条件,就可以运行示例函数了。运行方法是执行 ​​go test -v​​​,但是你可以不加 ​​-v​​ 选项,加上它只是为了输出更多细节。

4. 总结掌握 type 关键字初步了解 go test

练习:

写一个​​Second​​​ 和​​Minute​​ 互转程序,并写一份测试文件。尝试将 conv_test.go 里的​​// Output:​​ 后面的输出修改成其它值,比如
// Output:
// 32F = 0.00C

修改为

// Output:
// 32F = 0C

再运行 ​​go test -v​​ 看看输出。


上一篇: 二叉树旋转 下一篇: 手机怎么远程登录云服务器?