从C++到Go(三)
运算符
++
和--
运算符不能在表达式中使用,只能在语句中使用。你不能编写如c = *p++
的代码。*p++
被解析为(*p)++。
Go的运算符优先级和C++不同。例如,在Go中,4 & 3 << 1
为0
, 而在C++中为4
。
Go运算符优先级:
1. * / % << >> & &^
2. + - | ^
3. == != < <= > >=
4. &&
5. ||
C++运算符优先级 (only relevant operators):
1. * / %
2. + -
3. << >>
4. < <= > >=
5. == !=
6. &
7. ^
8. |
9. &&
10. ||
常量
在Go中,常量可以是*无类型(untyped)*的。如果在声明中未给定类型,并且初始化表达式仅使用无类型的常量,那么这甚至适用于以const声明的常量。从无类型常量得来的值,当他用于需要一个类型值的上下文中时,会变成有类型的值。这个规则使常量使用起来更自由,无需常规的隐式类型转换。
var a uint
f(a + 1) // 无类型数值常量"1"变成有类型的uint
对于无类型数值常量或常量表达式的大小,语言本身不强加任何限制。仅当在需要类型常量中使用常量时才被限制。
const huge = 1 << 100
f(huge >> 98)
Go不支持枚举。作为替换,你可以使用iota
在单独的const
声明中来获得一系列的递增值。当为const
省略初始化表达式时,它将重用前面的表达式。
const (
red = iota // red == 0
blue // blue == 1
green // green == 2
)
类型
C++和Go很类似,但不完全相同。C++的内置类型:有符号和无符号整数,32位和64位浮点数,结构体,指针等。在Go中,uint8
,int64
,和类型名称的整数类型是语言的一部分,而不是建立在其大小取决于具体实现的整数之上(例如long long
)。Go还提供了本地的string
,map
和channel
类型以及一流的数组和切片。字符串使用Unicode编码而不是ASCII。
Go比C++更加强类型,特别地,在Go中不存在隐式类型转换,只有显示类型转换。这提供了额外的安全性和自由,但要付出一些额外的打字费用。在Go中也没有union
,因为这将会颠覆类型系统。然而,Go中的interface{}
(将在下面讲解)提供了一个类型安全的代替品。
C++和Go都支持类型别名(在C++中为typedef
,在Go中为type
)。然而,与C++不同的是,Go对待别名为不同的类型。因此,以下代码在C++中有效:
// C++
typedef double position;
typedef double velocity;
position pos = 218.0;
velocity vel = -9.8;
pos += vel;
但是这在Go中无效:
type position float64
type velocity float64
var pos position = 218.0
var vel velocity = -9.8
pos += vel // 无效: 类型不匹配
// pos += position(vel) // 有效
即使对于非别名类型也是如此:一个int
和一个uint
不能在一个没有显式类型转换的表达式中使用。
与C++不同,Go不允许指针转换成整数或从整数转换而来。然而,Go的unsafe
包能够让你在必要时显式地绕过这个在安全机制(例如,用于低级系统的代码)。
切片
从概念上来说,一个切片是一个由三个字段组成的结构体:指向数组的指针,长度和容量。切片支持通过[]
运算符去访问底层数组的元素。内置函数len
返回切片的长度。内置函数cap
返回切片的容量。
给定一个数组或另一个切片,可以通过a[i:j]
来创建一个新的切片。这将创建一个引用a
的新的切片,起始位置为i
,结束位置为j
之前。它的长度为j - i
。如果i
被忽略,切片将从0
开始。如果j
被忽略,切片将结束于len(a)
。新的切片和a
引用相同的数组。该语句的两个含义是:①使用a
可以看到使用新切片进行的更改,并且②创建切片的开销是很低的;不需要拷贝底层数组。新切片的容量是a
的容量减i
。一个数组的容量是这个数组的长度。
这意味着Go在某些情况下使用切片,而C ++使用指针。如果你创建一个类型为[100]byte
的值(一个100个byte的数组)并且你想将他传递给一个函数但不想拷贝该数组,你应该将函数参数的类型声明为[]byte
,然后传递数组的切片(a[:]
,将传递整个数组)。与C++不同,不需要传递数组的长度;它可以通过len
函数获得。
切片语法也可以用于一个字符串。它返回一个新字符串,它的值为原始字符串的一个字串。因为字符串是不可变的,所以字符串切片可以实现为无需为切片的内容分配新的存储空间。