mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2024-11-28 09:09:07 +00:00
Merge branch 'master' of github.com:gopl-zh/gopl-zh.github.com
This commit is contained in:
commit
d4358fe46f
@ -8,7 +8,7 @@ Go语言同时提供了有符号和无符号类型的整数运算。这里有int
|
|||||||
|
|
||||||
Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
|
Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。这两个名称可以互换使用。同样byte也是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
|
||||||
|
|
||||||
最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。我们将在第十三章的unsafe包相关部分看到类似的例子。
|
最后,还有一种无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。uintptr类型只有在底层编程时才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方。我们将在第十三章的unsafe包相关部分看到类似的例子。
|
||||||
|
|
||||||
不管它们的具体大小,int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是不同的类型,即使int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然。
|
不管它们的具体大小,int、uint和uintptr是不同类型的兄弟类型。其中int和int32也是不同的类型,即使int的大小也是32bit,在需要将int当作int32类型的地方需要一个显式的类型转换操作,反之亦然。
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
一个布尔类型的值只有两种:true和false。if和for语句的条件部分都是布尔类型的值,并且==和<等比较操作也会产生布尔型的值。一元操作符`!`对应逻辑非操作,因此`!true`的值为`false`,更罗嗦的说法是`(!true==false)==true`,虽然表达方式不一样,不过我们一般会采用简洁的布尔表达式,就像用x来表示`x==true`。
|
一个布尔类型的值只有两种:true和false。if和for语句的条件部分都是布尔类型的值,并且==和<等比较操作也会产生布尔型的值。一元操作符`!`对应逻辑非操作,因此`!true`的值为`false`,更罗嗦的说法是`(!true==false)==true`,虽然表达方式不一样,不过我们一般会采用简洁的布尔表达式,就像用x来表示`x==true`。
|
||||||
|
|
||||||
布尔值可以和&&(AND)和||(OR)操作符结合,并且可能会有短路行为:如果运算符左边值已经可以确定整个布尔表达式的值,那么运算符右边的值将不在被求值,因此下面的表达式总是安全的:
|
布尔值可以和&&(AND)和||(OR)操作符结合,并且有短路行为:如果运算符左边值已经可以确定整个布尔表达式的值,那么运算符右边的值将不在被求值,因此下面的表达式总是安全的:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
s != "" && s[0] == 'x'
|
s != "" && s[0] == 'x'
|
||||||
@ -47,6 +47,3 @@ func btoi(b bool) int {
|
|||||||
// itob reports whether i is non-zero.
|
// itob reports whether i is non-zero.
|
||||||
func itob(i int) bool { return i != 0 }
|
func itob(i int) bool { return i != 0 }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
可以通过十六进制或八进制转义在字符串面值包含任意的字节。一个十六进制的转义形式是\xhh,其中两个h表示十六进制数字(大写或小写都可以)。一个八进制转义形式是\ooo,包含三个八进制的o数字(0到7),但是不能超过`\377`(译注:对应一个字节的范围,十进制为255)。每一个单一的字节表达一个特定的值。稍后我们将看到如何将一个Unicode码点写到字符串面值中。
|
可以通过十六进制或八进制转义在字符串面值包含任意的字节。一个十六进制的转义形式是\xhh,其中两个h表示十六进制数字(大写或小写都可以)。一个八进制转义形式是\ooo,包含三个八进制的o数字(0到7),但是不能超过`\377`(译注:对应一个字节的范围,十进制为255)。每一个单一的字节表达一个特定的值。稍后我们将看到如何将一个Unicode码点写到字符串面值中。
|
||||||
|
|
||||||
一个原生的字符串面值形式是`...`,使用反引号```代替双引号。在原生的字符串面值中,没有转义操作;全部的内容都是字面的意思,包含退格和换行,因此一个程序中的原生字符串面值可能跨越多行(译注:在原生字符串面值内部是无法直接写```字符的,可以用八进制或十六进制转义或+"```"链接字符串常量完成)。唯一的特殊处理是会删除回车以保证在所有平台上的值都是一样的,包括那些把回车也放入文本文件的系统(译注:Windows系统会把回车和换行一起放入文本文件中)。
|
一个原生的字符串面值形式是\`...\`,使用反引号代替双引号。在原生的字符串面值中,没有转义操作;全部的内容都是字面的意思,包含退格和换行,因此一个程序中的原生字符串面值可能跨越多行(译注:在原生字符串面值内部是无法直接写\`字符的,可以用八进制或十六进制转义或+"\`"链接字符串常量完成)。唯一的特殊处理是会删除回车以保证在所有平台上的值都是一样的,包括那些把回车也放入文本文件的系统(译注:Windows系统会把回车和换行一起放入文本文件中)。
|
||||||
|
|
||||||
原生字符串面值用于编写正则表达式会很方便,因为正则表达式往往会包含很多反斜杠。原生字符串面值同时被广泛应用于HTML模板、JSON面值、命令行提示信息以及那些需要扩展到多行的场景。
|
原生字符串面值用于编写正则表达式会很方便,因为正则表达式往往会包含很多反斜杠。原生字符串面值同时被广泛应用于HTML模板、JSON面值、命令行提示信息以及那些需要扩展到多行的场景。
|
||||||
|
|
||||||
@ -38,8 +38,3 @@ Usage:
|
|||||||
go command [arguments]
|
go command [arguments]
|
||||||
...`
|
...`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
### 3.5.2. Unicode
|
### 3.5.2. Unicode
|
||||||
|
|
||||||
在很久以前,世界还是比较简单的,起码计算机世界就只有一个ASCII字符集:美国信息交换标准代码。ASCII,更准确地说是美国的ASCII,使用7bit来表示128个字符:包含英文字母的大小写、数字、各种标点符号和设置控制符。对于早期的计算机程序来说,这些就足够了,但是这也导致了世界上很多其他地区的用户无法直接使用自己的符号系统。随着互联网的发展,混合多种语言的数据变得很常见(译注:比如本身的英文原文或中文翻译都包含了ASCII、中文、日文等多种语言字符)。如何有效处理这些包含了各种语言的丰富多样的文本数据呢?
|
在很久以前,世界还是比较简单的,起码计算机世界就只有一个ASCII字符集:美国信息交换标准代码。ASCII,更准确地说是美国的ASCII,使用7bit来表示128个字符:包含英文字母的大小写、数字、各种标点符号和设备控制符。对于早期的计算机程序来说,这些就足够了,但是这也导致了世界上很多其他地区的用户无法直接使用自己的符号系统。随着互联网的发展,混合多种语言的数据变得很常见(译注:比如本身的英文原文或中文翻译都包含了ASCII、中文、日文等多种语言字符)。如何有效处理这些包含了各种语言的丰富多样的文本数据呢?
|
||||||
|
|
||||||
答案就是使用Unicode( http://unicode.org ),它收集了这个世界上所有的符号系统,包括重音符号和其它变音符号,制表符和回车符,还有很多神秘的符号,每个符号都分配一个唯一的Unicode码点,Unicode码点对应Go语言中的rune整数类型(译注:rune是int32等价类型)。
|
答案就是使用Unicode( http://unicode.org ),它收集了这个世界上所有的符号系统,包括重音符号和其它变音符号,制表符和回车符,还有很多神秘的符号,每个符号都分配一个唯一的Unicode码点,Unicode码点对应Go语言中的rune整数类型(译注:rune是int32等价类型)。
|
||||||
|
|
||||||
在第八版本的Unicode标准收集了超过120,000个字符,涵盖超过100多种语言。这些在计算机程序和数据中是如何体现的呢?通用的表示一个Unicode码点的数据类型是int32,也就是Go语言中rune对应的类型;它的同义词rune符文正是这个意思。
|
在第八版本的Unicode标准收集了超过120,000个字符,涵盖超过100多种语言。这些在计算机程序和数据中是如何体现的呢?通用的表示一个Unicode码点的数据类型是int32,也就是Go语言中rune对应的类型;它的同义词rune符文正是这个意思。
|
||||||
|
|
||||||
我们可以将一个符文序列表示为一个int32序列。这种编码方式叫UTF-32或UCS-4,每个Unicode码点都使用同样的大小32bit来表示。这种方式比较简单统一,但是它会浪费很多存储空间,因为大数据计算机可读的文本是ASCII字符,本来每个ASCII字符只需要8bit或1字节就能表示。而且即使是常用的字符也远少于65,536个,也就是说用16bit编码方式就能表达常用字符。但是,还有其它更好的编码方法吗?
|
我们可以将一个符文序列表示为一个int32序列。这种编码方式叫UTF-32或UCS-4,每个Unicode码点都使用同样的大小32bit来表示。这种方式比较简单统一,但是它会浪费很多存储空间,因为大数据计算机可读的文本是ASCII字符,本来每个ASCII字符只需要8bit或1字节就能表示。而且即使是常用的字符也远少于65,536个,也就是说用16bit编码方式就能表达常用字符。但是,还有其它更好的编码方法吗?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ for range s {
|
|||||||
|
|
||||||
UTF8字符串作为交换格式是非常方便的,但是在程序内部采用rune序列可能更方便,因为rune大小一致,支持数组索引和方便切割。
|
UTF8字符串作为交换格式是非常方便的,但是在程序内部采用rune序列可能更方便,因为rune大小一致,支持数组索引和方便切割。
|
||||||
|
|
||||||
string接受到[]rune的类型转换,可以将一个UTF8编码的字符串解码为Unicode字符序列:
|
将[]rune类型转换应用到UTF8编码的字符串,将返回字符串编码的Unicode码点序列:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
// "program" in Japanese katakana
|
// "program" in Japanese katakana
|
||||||
|
@ -109,7 +109,7 @@ func Join(s [][]byte, sep []byte) []byte
|
|||||||
|
|
||||||
它们之间唯一的区别是字符串类型参数被替换成了字节slice类型的参数。
|
它们之间唯一的区别是字符串类型参数被替换成了字节slice类型的参数。
|
||||||
|
|
||||||
bytes包还提供了Buffer类型用于字节slice的缓存。一个Buffer开始是空的,但是随着string、byte或[]byte等类型数据的写入可以动态增长,一个bytes.Buffer变量并不需要处理化,因为零值也是有效的:
|
bytes包还提供了Buffer类型用于字节slice的缓存。一个Buffer开始是空的,但是随着string、byte或[]byte等类型数据的写入可以动态增长,一个bytes.Buffer变量并不需要初始化,因为零值也是有效的:
|
||||||
|
|
||||||
<u><i>gopl.io/ch3/printints</i></u>
|
<u><i>gopl.io/ch3/printints</i></u>
|
||||||
```Go
|
```Go
|
||||||
|
@ -63,7 +63,7 @@ fmt.Println(t) // "left foot"
|
|||||||
s[0] = 'L' // compile error: cannot assign to s[0]
|
s[0] = 'L' // compile error: cannot assign to s[0]
|
||||||
```
|
```
|
||||||
|
|
||||||
不变性意味如果两个字符串共享相同的底层数据的话也是安全的,这使得复制任何长度的字符串代价是低廉的。同样,一个字符串s和对应的子字符串切片s[7:]的操作也可以安全地共享相同的内存,因此字符串切片操作代价也是低廉的。在这两种情况下都没有必要分配新的内存。 图3.4演示了一个字符串和两个字串共享相同的底层数据。
|
不变性意味如果两个字符串共享相同的底层数据的话也是安全的,这使得复制任何长度的字符串代价是低廉的。同样,一个字符串s和对应的子字符串切片s[7:]的操作也可以安全地共享相同的内存,因此字符串切片操作代价也是低廉的。在这两种情况下都没有必要分配新的内存。 图3.4演示了一个字符串和两个子串共享相同的底层数据。
|
||||||
|
|
||||||
|
|
||||||
{% include "./ch3-05-1.md" %}
|
{% include "./ch3-05-1.md" %}
|
||||||
@ -75,6 +75,3 @@ s[0] = 'L' // compile error: cannot assign to s[0]
|
|||||||
{% include "./ch3-05-4.md" %}
|
{% include "./ch3-05-4.md" %}
|
||||||
|
|
||||||
{% include "./ch3-05-5.md" %}
|
{% include "./ch3-05-5.md" %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ func TurnDown(v *Flags) { *v &^= FlagUp }
|
|||||||
func SetBroadcast(v *Flags) { *v |= FlagBroadcast }
|
func SetBroadcast(v *Flags) { *v |= FlagBroadcast }
|
||||||
func IsCast(v Flags) bool { return v&(FlagBroadcast|FlagMulticast) != 0 }
|
func IsCast(v Flags) bool { return v&(FlagBroadcast|FlagMulticast) != 0 }
|
||||||
|
|
||||||
unc main() {
|
func main() {
|
||||||
var v Flags = FlagMulticast | FlagUp
|
var v Flags = FlagMulticast | FlagUp
|
||||||
fmt.Printf("%b %t\n", v, IsUp(v)) // "10001 true"
|
fmt.Printf("%b %t\n", v, IsUp(v)) // "10001 true"
|
||||||
TurnDown(&v)
|
TurnDown(&v)
|
||||||
|
@ -37,7 +37,7 @@ fmt.Println(5 / 9 * (f - 32)) // "0"; 5/9 is an untyped integer, 0
|
|||||||
fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 is an untyped float
|
fmt.Println(5.0 / 9.0 * (f - 32)) // "100"; 5.0/9.0 is an untyped float
|
||||||
```
|
```
|
||||||
|
|
||||||
只有常量可以是无类型的。当一个无类型的常量被赋值给一个变量的时候,就像上面的第一行语句,或者是像其余三个语句中右边表达式中含有明确类型的值,无类型的常量将会被隐式转换为对应的类型,如果转换合法的话。
|
只有常量可以是无类型的。当一个无类型的常量被赋值给一个变量的时候,就像下面的第一行语句,或者出现在有明确类型的变量声明的右边,如下面的其余三行语句,无类型的常量将会被隐式转换为对应的类型,如果转换合法的话。
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
var f float64 = 3 + 0i // untyped complex -> float64
|
var f float64 = 3 + 0i // untyped complex -> float64
|
||||||
@ -69,7 +69,7 @@ const (
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
对于一个没有显式类型的变量声明语法(包括短变量声明语法),无类型的常量会被隐式转为默认的变量类型,就像下面的例子:
|
对于一个没有显式类型的变量声明(包括简短变量声明),常量的形式将隐式决定变量的默认类型,就像下面的例子:
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
i := 0 // untyped integer; implicit int(0)
|
i := 0 // untyped integer; implicit int(0)
|
||||||
@ -78,7 +78,9 @@ f := 0.0 // untyped floating-point; implicit float64(0.0)
|
|||||||
c := 0i // untyped complex; implicit complex128(0i)
|
c := 0i // untyped complex; implicit complex128(0i)
|
||||||
```
|
```
|
||||||
|
|
||||||
注意默认类型是规则的:无类型的整数常量默认转换为int,对应不确定的内存大小,但是浮点数和复数常量则默认转换为float64和complex128。Go语言本身并没有不确定内存大小的浮点数和复数类型,而且如果不知道浮点数类型的话将很难写出正确的数值算法。
|
注意有一点不同:无类型整数常量转换为int,它的内存大小是不确定的,但是无类型浮点数和复数常量则转换为内存大小明确的float64和complex128。
|
||||||
|
如果不知道浮点数类型的内存大小是很难写出正确的数值算法的,因此Go语言不存在整型类似的不确定内存大小的浮点数和复数类型。
|
||||||
|
|
||||||
|
|
||||||
如果要给变量一个不同的类型,我们必须显式地将无类型的常量转化为所需的类型,或给声明的变量指定明确的类型,像下面例子这样:
|
如果要给变量一个不同的类型,我们必须显式地将无类型的常量转化为所需的类型,或给声明的变量指定明确的类型,像下面例子这样:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user