Golang学习笔记3(数据类型篇)| 青训营

142 阅读6分钟

基础数据类型

整型

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中函数的使用方法