Files
the-way-to-go_ZH_CN/eBook/04.5.md
2013-06-09 19:39:15 +08:00

335 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#4.5 基本类型和运算符
我们将在这个部分讲解有关布尔型、数字型和字符型的相关知识。
表达式是一种特定的类型的值,它可以由其它的值以及运算符组合而成。每个类型都定义了可以和自己结合的运算符集合,如果你使用了不在这个集合中的运算符,则会在编译时获得编译错误。
一元运算符只可以用于一个值的操作(作为后缀),而二元运算符则可以和两个值或者操作数结合(作为中缀)。
只有两个类型相同的值才可以和二元运算符结合另外要注意的是Go 是强类型语言,因此不会进行隐式转换,任何不同类型之间的转换都必须显式说明(第 4.2 节。Go 不存在像 C 和 Java 那样的运算符重载,表达式的解析顺序是从左至右。
你可以在第 4.5.3 节找到有关运算符优先级的相关信息,优先级越高的运算符在条件相同的情况下将被优先执行。但是你可以通过使用括号将其中的表达式括起来,以人为地提升某个表达式的运算优先级。
##4.5.1 布尔类型 bool
一个简单的例子:`var b bool = true`
布尔型的值只可以是常量 true 或者 false。
两个类型相同的值可以使用相等 `==` 或者不等 `!=` 运算符来进行比较并获得一个布尔型的值。
当相等运算符两边的值是完全相同的值的时候会返回 true否则返回 false并且只有在两个的值的类型相同的情况下才可以使用。
示例:
var aVar = 10
aVar == 5 -> false
aVar == 10 -> true
当不等运算符两边的值是不同的时候会返回 true否则返回 false。
示例:
var aVar = 10
aVar != 5 -> true
aVar != 10 -> false
Go 对于值之间的比较有非常严格的限制只有两个类型相同的值才可以进行比较如果值的类型是接口interface第 11 章),它们也必须都实现了相同的接口。如果其中一个值是常量,那么另外一个值的类型必须和该常量类型相兼容的。如果以上条件都不满足,则其中一个值的类型必须在被转换为和另外一个值的类型相同之后才可以进行比较。
布尔型的常量和变量也可以通过和逻辑运算符(非 `!`、和 `&&`、或 `||`)结合来产生另外一个布尔值,这样的逻辑语句就其本身而言,并不是一个完整的 Go 语句。
逻辑值可以被用于条件结构中的条件语句(第 5 章),以便测试某个条件是否满足。另外,和 `&&`、或 `||` 与相等 `==` 或不等 `!=` 属于二元运算符,而非 `!` 属于一元运算符。在接下来的内容中,我们会使用 T 来代表条件符合的语句,用 F 来代表条件不符合的语句。
Go 语言中包含以下逻辑运算符:
非运算符:`!`
!T -> false
!F -> true
非运算符用于取得和布尔值相反的结果。
和运算符:`&&`
T && T -> true
T && F -> false
F && T -> false
F && F -> false
只有当两边的值都为 true 的时候,和运算符的结果才是 true。
或运算符:`||`
T || T -> true
T || F -> true
F || T -> true
F || F -> false
只有当两边的值都为 false 的时候,或运算符的结果才是 false其中任意一边的值为 true 就能够使得该表达式的结果为 true。
在 Go 语言中,&& 和 || 是具有快捷性质的运算符,当运算符左边表达式的值已经能够决定整个表达式的值的时候(&& 左边的值为 false|| 左边的值为 true运算符右边的表达式将不会被执行。利用这个性质如果你有多个条件判断应当将计算过程较为复杂的表达式放在运算符的右侧以减少不必要的运算。
利用括号同样可以升级某个表达式的运算优先级。
在格式化输出时,你可以使用 `%t` 来表示你要输出的值为布尔型。
布尔值以及任何结果为布尔值的表达式最常用在条件结构的条件语句中例如if、for 和 switch 结构(第 5 章)。
对于布尔值的好的命名能够很好地提升代码的可读性,例如以 `is` 或者 `Is` 开头的 `isSorted``isFinished``isVisivle`,使用这样的命名能够在阅读代码的获得阅读正常语句一样的良好体验,例如标准库中的 `unicode.IsDigit(ch)`(第 4.5.5 节)。
##4.5.2 数字类型
###4.5.2.1 整型 int 和浮点型 float
Go 语言支持整型和浮点型数字,并且原生支持复数,其中位的运算采用补码(二的补码,详情参见:[http://en.wikipedia.org/wiki/Two's_complement](http://en.wikipedia.org/wiki/Two's_complement))。
Go 也有基于架构的类型例如int、uint 和 uintptr。
这些类型的长度都是根据运行程序所在的操作系统类型所决定的:
- `int``uint` 在 32 位操作系统上,它们均使用 32 位4 个字节),在 64 位操作系统上,它们均使用 64 位8 个字节)。
- `uintptr` 的长度被设定为足够存放一个指针即可。
Go 语言中没有 float 类型。
与操作系统架构无关的类型都有固定的大小,并在类型的名称中就可以看出来:
整数:
- int8-128 -> 127
- int16-32768 -> 32767
- int32-2,147,483,648 -> 2,147,483,647
- int64-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807
无符号整数:
- uint80 -> 255
- uint160 -> 65,535
- uint320 -> 4,294,967,295
- uint640 -> 18,446,744,073,709,551,615
浮点型IEEE-754 标准):
- float32+- 1e-45 -> +- 3.4 * 1e38
- float64+- 5 * 1e-324 -> 107 * 1e308
int 型是计算最快的一种类型。
整型的零值为 0浮点型的零值为 0.0。
float32 精确到小数点后 7 位float64 精确到小数点后 15 位。由于精确度的缘故,你在使用 `==` 或者 `!=` 来比较浮点数时应当非常小心。你最好在正式使用前测试对于精确度要求较高的运算。
你应该尽可能地使用 float64因为 `math` 包中所有有关数学运算的函数都会要求接收这个类型。
你可以通过增加前缀 0 来表示 8 进制数077增加前缀 0x 来表示 16 进制数0xFF以及使用 e 来表示 10 的连乘(如: 1e3 = 1000或者 6.022e23 = 6.022 x 1e23
你可以使用 `a := uint64(0)` 来同时完成类型转换和赋值操作,这样 a 的类型就是 uint64。
Go 中不允许不同类型之间的混合使用,但是对于常量的类型限制非常少,因此允许常量之间的混合使用,下面这个程序很好地解释了这个现象(该程序无法通过编译):
Example 4.8 [type_mixing.go](examples/chapter_4/type_mixing.go)
package main
func main() {
var a int
var b int32
a = 15
b = a + a // 编译错误
b = b + 5 // 因为 5 是常量,所以可以通过编译
}
如果你尝试编译该程序,则将得到编译错误 `cannot use a + a (type int) as type int32 in assignment`
同样地int16 也不能够被隐式转换为 int32。
下面这个程序展示了通过显示转换来避免这个问题(第 4.2 节)。
Example 4.9 [casting.go](examples/chapter_4/casting.go)
package main
import “fmt”
func main() {
var n int16 = 34
var m int32
// compiler error: cannot use n (type int16) as type int32 in assignment
//m = n
m = int32(n)
fmt.Printf(“32 bit int is: %d\n”, m)
fmt.Printf(“16 bit int is: %d\n”, n)
}
// the output is:
32 bit int is: 34
16 bit int is: 34
**格式化说明符**
在格式化字符串里,`%d` 用于格式化整数(`%x``%X` 用于格式化 16 进制表示的数字),`%g` 用于格式化浮点型(`%f` 输出浮点数,`%e` 输出科学计数表示法),`%0d` 用于规定输出定长的整数,其中开头的数字 0 是必须的。
`%n.mg` 用于表示数字 n 并精确到小数点后 m 位,除了使用 g 之外,还可以使用 e 或者 f例如使用格式化字符串 `%5.2e` 来输出 3.4 的结果为 `3.40e+00`
**数字值转换**
当进行类似 `a32bitInt = int32(a32Float)` 的转换时,小数点后的数字将被丢弃。这种情况一般发生当从取值范围较大的类型转换为取值范围较小的类型时,或者你可以写一个专门用于处理类型转换的函数来确保没有发生精度的丢失。下面这个例子展示如何安全地从 int 型转换为 int8
func Uint8FromInt(n int) (uint8, error) {
if 0 <= n && n <= math.MaxUint8 { // conversion is safe
return uint8(n), nil
}
return 0, fmt.Errorf(“%d is out of the uint8 range”, n)
}
或者安全地从 float64 转换为 int
func IntFromFloat64(x float64) int {
if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
whole, fraction := math.Modf(x)
if fraction >= 0.5 {
whole++
}
return int(whole)
}
panic(fmt.Sprintf(“%g is out of the int32 range”, x))
}
不过如果你实际存的数字超出你要转换到的类型的取值范围的话,则会引发 panic第 13.2 节)。
**问题 4.1 int 和 int64 是相同的类型吗?**
###4.5.2.2 复数
Go 拥有以下复数类型:
complex64 (32 位实数和虚数)
complex128 (64 位实数和虚数)
复数使用 `re+imI` 来表示,其中 `re` 代表实数部分,`im` 代表虚数部分I 代表根号负 1。
示例:
var c1 complex64 = 5 + 10i
fmt.Printf(“The value is: %v”, c1)
// 输出: 5 + 10i
如果 `re``im` 的类型均为 float32那么类型为 complex64 的复数 c 可以通过以下方式来获得:
c = complex(re, im)
函数 `real(c)``imag(c)` 可以分别获得相应的实数和虚数部分。
在使用格式化标识符时,可以使用 `%v` 来表示复数,但当你希望只表示其中的一个部分的时候需要使用 `%f`
复数支持和其它数字类型一样的运算。当你使用等号 `==` 或者不等号 `!=` 对复数进行比较运算时,注意对精确度的把握。`cmath` 包中包含了一些操作复数的公共方法。如果你对内存的要求不是特别高,最好使用 complex128 作为计算类型,因为相关函数都使用这个类型的参数。
###4.5.2.3 位运算
位运算只能用于整数类型的变量,且需当它们拥有等长位模式时。
`%b` 是用于表示位的格式化标识符。
**二元运算符**
- 按位与 `&`
对应位置上的值经过和运算结果,具体参见和运算符,第 4.5.1 节,并将 Ttrue替换为 1将 Ffalse替换为 0
1 & 1 -> 1
1 & 0 -> 0
0 & 1 -> 0
0 & 0 -> 0
- 按位或 `|`
对应位置上的值经过或运算结果,具体参见或运算符,第 4.5.1 节,并将 Ttrue替换为 1将 Ffalse替换为 0
1 & 1 -> 1
1 & 0 -> 1
0 & 1 -> 1
0 & 0 -> 0
- 按位异或 `^`
对应位置上的值根据以下规则组合:
1 & 1 -> 0
1 & 0 -> 1
0 & 1 -> 1
0 & 0 -> 0
- 位清除 `&^`:将指定位置上的值设置为 0。
**一元运算符**
- 按位补足 `^`
该运算符与异或运算符一同使用,即 `m^x`,对于无符号 x 使用“全部位设置为 1”对于有符号 x 时使用 `m=-1`。例如:
^2 = ^10 = -01 ^ 10 = -11
- 位左移 `<<`
- 用法:`bitP << n`
- `bitP` 的位向左移动 n 位,右侧空白部分使用 0 填充;如果 n 等于 2则结果是 2 的相应倍数,即 2 的 n 次方。例如:
1 << 10 // 等于 1 KB
1 << 20 // 等于 1 MB
1 << 30 // 等于 1 GB
- 位右移 `>>`
- 用法`bitP >> n`
- `bitP` 的位向右移动 n 左侧空白部分使用 0 填充如果 n 等于 2则结果是当前值除以 2 n 次方
当希望把结果赋值给第一个操作数时可以简写为 `a <<= 2` 或者 `b ^= a & 0xffffffff`
**位左移常见实现存储单位的用例**
使用位左移与 iota 计数配合可优雅地实现存储单位的常量枚举
type ByteSize float64
const (
_ = iota // 通过赋值给空白标识符来忽略值
KB ByteSize = 1<<(10*iota)
MB
GB
TB
PB
EB
ZB
YB
)
**在通讯中使用位左移表示标识的用例**
type BitFlag int
const (
Active BitFlag = 1 << iota // 1 << 0 == 1
Send // 1 << 1 == 2
Receive // 1 << 2 == 4
)
flag := Active | Send // == 3
###4.5.2.4 逻辑运算符
Go 中拥有以下逻辑运算符`==``!=` 4.5.1 )、`<``<=``>``>=`
它们之所以被称为逻辑运算符是因为它们的运算结果总是为布尔值 `bool`例如
b3:= 10 > 5 // b3 is true
###4.5.2.5 算术运算符
##啊哦,亲,你看得也太快了。。。还没翻译完呢 0 0
要不等到 ***2013 年 6 月 11 日*** 再来看看吧~~
这里还有一些其它的学习资源噢~
- [《Go编程基础》](https://github.com/Unknwon/go-fundamental-programming):已更新至 [第10课](https://github.com/Unknwon/go-fundamental-programming/blob/master/lecture10/lecture10.md)
- [《Go Web编程》](https://github.com/astaxie/build-web-application-with-golang)
神马?你说你不想学习?那好吧,去逛逛看看行情也行~
- [Go Walker](http://gowalker.org) **Go 项目文档在线浏览工具**
- [Golang中文社区](http://bbs.mygolang.com/forum.php)
- [Go语言学习园地](http://studygolang.com/)
- [Golang中国](http://golang.tc)
##链接
- [目录](directory.md)
- 上一节:[变量](04.4.md)
- 下一节:[字符串](04.6.md)