原文:http://golang.org
翻译:刘金雨/刘云涛 <yuntao.liu#gmail.com> http://www.log4think.com

数据类型 Types


Go有一些常见的数据类型,例如 int 和 float,其值采用机器“适用”的大小来表示。也有定义了明确大小的数据类型,例如 int8、float64 等,以及无符号整数类型,例如 uint、uint32 等。这些都是完全不同的数据类型,即使 int 和int32 都是32位整数,但它们是不同的类型。对于表示字符串元素的类型 byte 和uint8 也是同样如此。
说到字符串( string ),这也是一个内置的数据类型。 字符串的值不仅仅是一个byte 的数组,它的值是不可改变的。一旦确定了一个字符串的值,就不能再修改了。但一个字符串变量的值可以通过重新赋值来改变。下面这段来自 strings.go的代码是合法的:
 
11        s := "hello";
12        if s[1] != 'e' { os.Exit(1) }
13        s = "good bye";
14        var p *string = &s;
15        *p = "ciao";
然而下面这段代码是非法的,因为它试图修改一个字符串的值:
 
    s[0] = 'x';
    (*p)[1] = 'y';
按照C++的说法,Go的字符串有点类似带了 const 修饰符,指向字符串的指针也类似于一个 const 字符串的引用(reference).
没错,前面看到的那些是指针,然而Go语言中的指针在用法方面有所简化,后文会提到。
数组的声明如下所示:
 
    var arrayOfInt [10]int;
数组同字符串一样是“值”,但是却是可变的。与C不同的是,C语言中 arrayOfInt可以当做一个指向int的指针来用。在Go中,因为数组是“值”,因此 arrayOfInt被看做(也被用做)指向数组的指针。
数组的大小是其数据类型的一部分。但是,你可以声明一个 slice 变量,然后可以用一个指向具有相同元素类型的数组指针给它赋值,更常见的是用一个形式为a[low : high]的 slice 表达式,该表达式表示下标从 low 到 high-1 的子数组。 Slice 类型类似数组,但没有显式指定大小 ([] 之于 [10]),用于表示一个隐性(通常是匿名的)数组。如果不同的 slice 都是表示同一个数组中的数据,它们可以共享该数组的内存,但不同的数组则永远不会共享内存数据。
Slice 在Go 程序中比数组更常见。它更灵活,并且具有引用的语义,效率也更高。其不足之处在于无法像数组一样精确控制存储方式,如果想在一个数据结构中保存一个具有100个元素的序列,应该采用数组。
当给函数传一个数组参数的时候,绝大多数情况下都会把参数声明为 slice 类型。当调用函数时,先取数组地址,然后Go会创建一个 slice 的引用,然后传这个引用过去。
可以用 slice 来写这个函数(来自 sum.go):
 
 
09    func sum(a []int) int {   // 返回一个整数
10        s := 0;
11        for i := 0; i < len(a); i++ {
12            s += a[i]
13        }
14        return s
15    }
之后这样来调用:
 
 
19        s := sum(&[3]int{1,2,3});  // a slice of the array is passed to sum
注意在sum()的参数列表后面加 int 定义了其返回值类型(int)。[3]int{1,2,3} 的形式是一个数据类型后面接一个大括号括起来的表达式,整个这个表达式构造出了一个值,这里是一个包含三个整数的数组。前面的 & 表示提取这个值的地址。这个地址会被隐性的转为一个 slice 传给 sum() 。
如果想创建一个数组,但希望编译器来帮你确定数组的大小,可以用 ... 作为数组大小:
 
    s := sum(&[...]int{1,2,3});
实际使用中,除非非常在意数据结构的存储方式,否则 slice 本身 (用[]且不带&) 就足够了:
 
    s := sum([]int{1,2,3});
除此之外还有map,可以这样初始化:
 
    m := map[string]int{"one":1 , "two":2}
sum还第一次出现了内置函数 len(),用于返回元素数量。可以用于字符串、数组、slice、map、map 和 channel.
此外, for 循环中的 range 也可以用于字符串、数组、slice、map、map 和 channel。例如
 
    for i := 0; i < len(a); i++ { ... }
遍历一个序列的每个元素,可以写成
 
    for i, v := range a { ... }
其中, i 会赋值为下标, v 会赋值为 a 中对应的值,Effective Go 中包含了更多的用法演示。

有疑问加站长微信联系(非本文作者)