基础数据类型
整型
Go语言同时提供了有符号和无符号类型的整数运算。这里有int8、int16、int32和int64四种截然不同大小的有符号整数类型,分别对应8、16、32、64bit大小的有符号整数,与此对应的是uint8、uint16、uint32和uint64四种无符号整数类型。当然,我们也可以直接使用int/uint来命名,这两种类型都有同样的大小,32或64bit,这取决于操作系统和编译器的位数
Go语言中的二元运算符与C中类似,按照优先级在下面给出:
* / % << >> & &^
+ - | ^
== != < <= > >=
&&
||
Go语言还提供了以下的bit位操作运算符,前面4个操作运算符并不区分是有符号还是无符号数:
& 位运算 AND
| 位运算 OR
^ 位运算 XOR
&^ 位清空(AND NOT)
<< 左移
>> 右移
对于数据类型不匹配的情况,通常使用类型转换操作T(x)转化为T类型,当然,在转换的过程中可能会造成数据的改动或是丢失精度:
f := 3.141 // a float64
i := int(f)
fmt.Println(f, i) // "3.141 3"
f = 1.14
fmt.Println(int(f)) // "1"
复数
Go语言提供了两种精度的复数类型:complex64和complex128,分别对应float32和float64两种浮点数精度。内置的complex函数用于构建复数,内建的real和imag函数分别返回复数的实部和虚部:
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x*y) // "(-5+10i)"
fmt.Println(real(x*y)) // "-5"
fmt.Println(imag(x*y)) // "10"
如果一个浮点数面值或一个十进制整数面值后面跟着一个i,例如3.14i或2i,它将构成一个复数的虚部,复数的实部是0
复数也可以用==和!=进行相等比较。只有两个复数的实部和虚部都相等的时候它们才是相等的
复合数据类型
数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的
数组的每个元素可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数
默认情况下,数组的每个元素都被初始化为元素类对应的零值,对于数字类型来说就是0。我们也可以使用数组字面值语法用一组值来初始化数组
var q [3]int = [3]int{1, 2, 3}
var r [3]int = [3]int{1, 2}
fmt.Println(r[2]) // "0"
Slice
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。
一个slice由三个部分构成:指针、长度和容量,指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。
Slice内置的append函数用于向slice追加元素:
var runes []rune
for _, r := range "Hello, 世界" {
runes = append(runes, r)
}
fmt.Printf("%q\n", runes) // 输出"['H' 'e' 'l' 'l' 'o' ',' ' ' '世' '界']"
Map
在Go语言中,一个map就是一个哈希表的引用,map类型可以写为map[K]V,其中K和V分别对应key和value。map中所有的key都有相同的类型,所有的value也有着相同的类型,但是key和value之间可以是不同的数据类型。
内置的make函数可以创建一个map:
ages := make(map[string]int) // mapping from strings to ints
我们也可以用map字面值的语法创建map,同时还可以指定一些最初的key/value:
ages := map[string]int{
"alice": 31,
"charlie": 34,
}
使用内置的delete函数可以删除元素:
delete(ages, "alice") // remove element ages["alice"]
通过key作为索引下标来访问map将产生一个value。如果key在map中是存在的,那么将得到与key对应的value;如果key不存在,那么将得到value对应类型的零值
但是我们要如何区分不存在返回的零值和已经存在的零值呢
可以像下面这样测试:
age, ok := ages["bob"]
if !ok { /* "bob" 不是该map中的key; age == 0. */ }
map的下标语法将产生两个值;第二个是一个布尔值,用于报告元素是否真的存在。布尔变量一般命名为ok,适合用于if条件判断部分
结构体
下面两个语句声明了一个叫Employee的命名的结构体类型,并且声明了一个Employee类型的变量dilbert:
type Employee struct {
ID int
Name string
Address string
}
var dilbert Employee
可以使用点操作符访问其中成员
JSON
在Golang中,JSON(JavaScript Object Notation)是一种常用的数据交换格式,用于在不同的系统之间传输和存储数据。Golang提供了内置的标准库encoding/json来处理JSON数据。
下面是一个简单的示例代码,演示了如何在Golang中使用encoding/json包进行JSON的编码和解码:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
// 编码为JSON
person := Person{Name: "Alice", Age: 25}
jsonData, err := json.Marshal(person)
if err != nil {
fmt.Println("JSON编码失败:", err)
return
}
fmt.Println(string(jsonData))
// 解码JSON
var decodedPerson Person
err = json.Unmarshal(jsonData, &decodedPerson)
if err != nil {
fmt.Println("JSON解码失败:", err)
return
}
fmt.Println(decodedPerson.Name, decodedPerson.Age)
}
在上面的示例中,我们定义了一个Person结构体,其中的字段使用了json标签来指定JSON的字段名。然后,我们使用json.Marshal函数将Person对象编码为JSON字符串,并使用json.Unmarshal函数将JSON字符串解码为Person对象。
通过使用encoding/json包,我们可以方便地在Golang中进行JSON的编码和解码操作,从而实现与其他系统的数据交互。
总结
本文主要介绍Golang中的数据类型,包括基础的和复合的类型,了解了基本的数据类型知识后,在下一章我们将继续了解程序设计中非常重要的部分——函数。
下一篇预告:Golang中函数的使用方法