基础数据类型

267 阅读11分钟

整形

int8 , int16 , int32 , int64 分别对应8、16、32、64bit大小的有符号整数,与此对应的是uint8uint16uint32uint64四种无符号整数类型。

当然,int 也是一个数据类型,虽然它也是 32bit 但是它和 int32 并不是一样的。

一个n-bit的有符号数的值域是从-2n-12n-1-1。无符号整数的所有bit位都用于表示非负数,值域是02n-1。例如,int8类型整数的值域是从-128127,而uint8类型整数的值域是从0255

另外,如果数据溢出,那么超出的高位bit将会被丢弃。

var u uint8 = 255
fmt.Println(u, u+1, u*u) // "255 0 1"

var i int8 = 127
fmt.Println(i, i+1, i*i) // "127 -128 1"

类型转换:

var x int8 = 1;
var y int16 = 2;
var z int = int(x)+int(y); //将x和y显示转换为int类型

浮点数

Go语言提供了两种精度的浮点数,float32float64

一个float32类型的浮点数可以提供大约6个十进制数的精度,而float64则可以提供约15个十进制数的精度;通常应该优先使用float64类型,因为float32类型的累计计算误差很容易扩散,并且float32能精确表示的正整数并不是很大(译注:因为float32的有效bit位只有23个,其它的bit位用于指数和符号;当整数大于23bit能表达的范围时,float32的表示将出现误差)

var f float32 = 16777216 // 1 << 24
fmt.Println(f == f+1)    // "true"!

复数

Go语言提供了两种精度的复数类型:complex64complex128,分别对应float32float64两种浮点数精度。内置的complex函数用于构建复数,内建的realimag函数分别返回复数的实部和虚部:

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"

当然也有更简单的方式声明复数:

x := 1+2i
y := 3+4i

布尔类型

一个布尔类型的值只有两种:truefalse。 需要注意的是:布尔值并不会隐式转换为数字值0或1,反之亦然。必须使用一个显式的if语句辅助转换。

字符串

字符串和c++的字符串类似; 但是go语言有一个内置的len函数返回字符串的字节数目:

s := "hello, world"
fmt.Println(len(s))     // "12"
fmt.Println(s[0], s[7]) // ('h' and 'w')

s[i] 返回的是第 i 个字节符,并不是第 i 个字符,因为对于非ASCII字符的UTF8编码会要两个或多个字节。

s[i:j] 表示基于原始的s字符串从第 i 个字节到第 j 个字节(不包含 j)生成一个新的字符串。生成的字符串包含 j-i 个字节。

fmt.Println(s[0:5]) // "hello"

同样,i 或者 j 都可以被忽略,当左边的被忽略的时候会采用 0 作为开始的位置,当右边被忽略的时候会采用 len(s) 作为结束的位置:

fmt.Println(s[:5]) // "hello"
fmt.Println(s[7:]) // "world"
fmt.Println(s[:])  // "hello, world"

同样的,类似于c++,可以使用 + 连接俩个字符串:

fmt.Println("hello" + s[5:]) // "hello, world"

在这里,字符串是不可修改的

s[0]='s' //这个操作将会报错:compile error: cannot assign to s[0]

字符串操

Contains()

判断字符串 s 中是否包含字符串 str,包含就返回真,否则返回假:

s := "hello"
str := "ll"

fmt.Println(strings.Contains(s,str)) //true

Count

找出字符串 str 在 s 中出现过几次,返回值为出现次数:

s := "hello"
str := "l"

fmt.Println(strings.Count(s,str)) //2

HasPrefix

判断字符串 s 是否以 str 为前缀开头,是则返回真:

s := "hello"
str := "he"

fmt.Println(strings.HasPrefix(s,str)) //true

HasSuffix

判断字符串 s 是否以 str 为后缀结尾,是则返回真:

s := "hello"
str := "llo"

fmt.Println(strings.HasSuffix(s,str)) //true

Index

在字符串 s 中查找 字符串 str 第一次出现的位置,返回下标索引,如果没有 str 则返回 -1

s := "hello"
str := "ll"

fmt.Println(strings.Index(s,str)) //2

Join

Join 是字符串拼接函数,虽然可以直接使用 + 进行拼接,但是Jion在处理数据量很大的时候更加占据优势。

将字符串数组 s 中的所有字符出以 str 的形式拼接起来:

func Join(s []string, sep string) string //函数形式

s := []string{"hel","lo"}
str := "-"

fmt.Println(strings.Join(s,str)) //hel-lo

Repeat

将字符串 s 重复 n 次并返回:

func Repeat(s string, count int) string //函数形式

s := "hello"

fmt.Println(strings.Index(s,2)) //hellohello

Replace

将字符串 s 中的 old 字符串 替换成 new 字符串,替换 n 个,如果 n 为 -1 ,则全部替换。

func Replace(s, old, new string, n int) string //函数形式

s := "hello"

fmt.Println(strings.Replace(s,"l","L",1)) //heLlo
fmt.Println(strings.Replace(s,"e","E",-1)) //hEllo

Split

将字符串 s 按照 str 来分割,并将分割结果储存到字符串数组中。

s := "h-e-l-l-o"

fmt.Println(strings.Replace(s,"-")) //[h e l l o]

//将字符串以 - 为分隔放到字符串数组中,没有 -

Tolower

将字符串 s 全部换成大写

fmt.Println(strings.ToLower("hello")) //HELLO

ToUpper

将字符串 s 全部转换成小写

fmt.Println(strings.ToLower("HELLOW")) //hello

原生字符面值

来自go语言圣经的参考:

一个原生的字符串面值形式是 `...` ,使用反引号代替双引号。在原生的字符串面值中,没有转义操作;全部的内容都是字面的意思,包含退格和换行,因此一个程序中的原生字符串面值可能跨越多行(译注:在原生字符串面值内部是无法直接写`字符的,可以用八进制或十六进制转义或+" ` "连接字符串常量完成)。唯一的特殊处理是会删除回车以保证在所有平台上的值都是一样的,包括那些把回车也放入文本文件的系统(译注:Windows系统会把回车和换行一起放入文本文件中)。

原生字符串面值用于编写正则表达式会很方便,因为正则表达式往往会包含很多反斜杠。原生字符串面值同时被广泛应用于HTML模板、JSON面值、命令行提示信息以及那些需要扩展到多行的场景。

const GoUsage = `Go is a tool for managing Go source code.

Usage:
    go command [arguments]
...`

常量

与c的常量一样,常量的值不能被修改。

声明方式为:

const 变量名 = 数值

当然也可以一次性声明多个常量:

const(
	e = 2.718
	pi = 3.14
)

数组

在go语言中,数组的定义基本与其他语言类似,都是一个固定长度的特定类型元素组成的序列。

声明方式为:

var 数组名 [数组长度] 数据类型

例如:

var a[3] int

默认情况下,所有值都被赋值为零。 也可以使用数组字面值语法在初始化的时候进行赋值:

var q[3] int = [3]int{1,2,3}
var r[3] int = [3]int{1,2} //此时第三个数的值为 0

上述的 q 数组的定义也可以简化为:

q := [...]int{1,2,3} 

这代表数组q的长度会根据初始化的个数来决定。

也可以根据索引值来进行初始化:

r := [...]int{99: -1}

这表示 r 数组有 100 个数,第 100 个数的值被赋值为 -1 。

在go语言中,如果两个数组的元素类型可以相互比较,那么数组类型也是可以进行相互比较的:

a := [2]int{1,2}
b := [...]int{1,3}

fmt.Println(a==b) //false

当然,如果数组的长度不一样,是不能进行比较的。

特别注意的是,当函数调用数组的时候,调用的是一个数组的副本, 我们不能直接对数组进行操作。

在go语言中,可以显性的传入一个数组指针,这样就可以直接对原数组进行修改:

func zero(ptr *[32]byte) {
    for i := range ptr {
        ptr[i] = 0
    }
}

//简洁方式初始化为零
func zero(ptr *[32]byte) {
    *ptr = [32]byte{}
}

在go语言中,数组是固定长度大小,使用起来不是很方便,除非在一些特定场合,一般使用 slice 来代替数组。

slice 切片

类似于一种可变长的数组。

切片的声明:

var 切片名 []数据类型

切片不需要说明长度

或者使用 make 函数创建切片:

var a []int = make([]int , 10) //创建一个长度为10的切片

a := make([]int , 10) //使用简写

初始化

s := []int{1,2,3} //字面值初始化

s := arr[st:ed] //在arr中创建一个切片,索引为st到ed

append 函数可以向切片里面追加扩容:

a := []int{1,2,3} //1,2,3
a = append(a,4) //1,2,3,4 

输出

可以直接使用 println 输出切片,不需要指出长度什么的:

fmt.Println(a) //[1 2 3 4]

map

哈希表,是一种数据结构。它可以在常数时间复杂度内完成检索、更新或者删除对应的 value。

map 的初始化为:

ages := make(map[string]int) //string为key,int为value
ages["alice"] = 31
ages["charlie"] = 34

也可以使用字面值初始化:

ages := map[string]int{
	"alice": 31,
	"cgarlie": 34,
}

可以使用 key 来访问 value:

fmt.Println(ages["ailce"]) //31
delete

可以使用 delete 函数进行删除操作:

delete(ages,"alice") //对应删除alice这对值

通过key作为索引下标来访问map将产生一个value。如果key在map中是存在的,那么将得到与key对应的value;如果key不存在,那么将得到value对应类型的零值。 这个规则很实用,但是有时候可能需要知道对应的元素是否真的是在map之中。例如,如果元素类型是一个数字,你可能需要区分一个已经存在的0,和不存在而返回零值的0,可以像下面这样测试:

age, ok := ages["bob"]
if !ok { /* "bob" is not a key in this map; age == 0. */ }
if age, ok := ages["bob"]; !ok { /* ... */ }

在这种场景下,map的下标语法将产生两个值;第二个是一个布尔值,用于报告元素是否真的存在。布尔变量一般命名为ok,特别适合马上用于if条件判断部分。

在go语言中没有 set ,但是可以使用 map 充当 set 来使用。因为 map 中的 key 也不能够重复。

结构体

结构体的生命:

type Employee struct{
	id      int
	name    string
	address string
}

var dilbert Employee

结构体的初始化也可以使用字面值:

type Point struct{x,y int}

p := Point{1,2}
q := Point{x:1 , y:2} //可以指定赋值
x := Point{x:1} //也可以只指定一部分,其他值初始化为零值

JSON

JSON是对JavaScript中各种类型的值——字符串、数字、布尔值和对象——Unicode本文编码。

这些基础类型可以通过JSON的数组和对象类型进行递归组合。一个JSON数组是一个有序的值序列,写在一个方括号中并以逗号分隔;一个JSON数组可以用于编码Go语言的数组和slice。一个JSON对象是一个字符串到值的映射,写成一系列的name:value对形式,用花括号包含并以逗号分隔;JSON的对象类型可以用于编码Go语言的map类型(key类型是字符串)和结构体。

boolean         true
number          -273.15
string          "She said \"Hello, BF\""
array           ["gold", "silver", "bronze"]
object          {"year": 1980,
                 "event": "archery",
                 "medals": ["gold", "silver", "bronze"]}

定义一个movie的数据类型(每个成员的首字母大写):

type Movie struct {
    Title  string
    Year   int  `json:"released"`//这个的作用是转化为json的时候将字段改为released而不是Year
    Color  bool `json:"color,omitempty"` 
    Actors []string
}

var movies = []Movie{
    {Title: "Casablanca", Year: 1942, Color: false,
        Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
    {Title: "Cool Hand Luke", Year: 1967, Color: true,
        Actors: []string{"Paul Newman"}},
    {Title: "Bullitt", Year: 1968, Color: true,
        Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
    // ...
}

可以使用 json.Marshal 函数转换为 JSON 格式:

data, err := json.Marshal(movies)
if err != nil {
    log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)

但是这个很难阅读,所以有另一个函数,为了生成便于阅读的格式,另一个json.MarshalIndent函数将产生整齐缩进的输出。该函数有两个额外的字符串参数用于表示每一行输出的前缀和每一个层级的缩进:

data, err := json.MarshalIndent(movies, "", "    ")
if err != nil {
    log.Fatalf("JSON marshaling failed: %s", err)
}
fmt.Printf("%s\n", data)

输出结果为:

[
    {
        "Title": "Casablanca",
        "released": 1942,
        "Actors": [
            "Humphrey Bogart",
            "Ingrid Bergman"
        ]
    },
    {
        "Title": "Cool Hand Luke",
        "released": 1967,
        "color": true,
        "Actors": [
            "Paul Newman"
        ]
    },
    {
        "Title": "Bullitt",
        "released": 1968,
        "color": true,
        "Actors": [
            "Steve McQueen",
            "Jacqueline Bisset"
        ]
    }
]

关于JSON的更加详细的解释:JSON - Go语言圣经 (golang-china.github.io)

文本和HTML模板

后续用到了再来补充