程序结构
类型
类型定义
type 类型名字 底层类型
类型的应用场景 ?
作用域 ?
一个声明语句将程序中的实体和一个名字关联,比如一个函数或一个变量。声明语句的作用域是指源代码中可以有效使用这个名字的范围。
声明语句的作用域对应的是一个源代码的文本区域;它是一个编译时的属性。
变量生命周期 ?
变量的生命周期指的是在程序运行期间变量有效存在的时间段
一个变量的生命周期是指程序运行时变量存在的有效时间段,在此时间区域内它可以被程序的其他部分引用;是一个运行时的概念。
基础数据类型
整型
- int
- int8
- int16
- int32
- int64
- uint
- uint8
- uint16
- uint32
- uint64
- uintptr
浮点
-
float32
-
float64
复数
-
complex64
-
complex128
布尔类型
- bool
字符串
一个字符串是一个不可改变的字节序列
常量
复合数据类型
数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,因此在Go语言中很少直接使用数组
package main
import (
"fmt"
)
func main() {
//定义
var a [10]int
var b [5]int
fmt.Printf("len(a)=%d,len(b)=%d\n", len(a), len(b))
//赋值
for i := 0; i < len(a); i++ {
a[i] = i + 1
}
//遍历
for i, data := range a {
fmt.Printf("a[%d] = %d\n", i, data)
}
//赋值并初始化
c := [3]int{1, 2} //未初始化的值为 0
d := [...]int{1, 2, 3} //通过初始化值确定数据长度
e := [5]int{2: 100, 4: 200} //通过索引好初始化元素,
fmt.Println(c, d, e)
//update,数组是值类型,每次传递都将产生一份副本
fmt.Println("test modify")
f := [5]int{1, 2, 3, 4, 5}
fmt.Println("before modify", f) //before modify [1 2 3 4 5]
modify(f)
fmt.Println("after modify", f) //after modify [1 2 3 4 5]
}
func modify(array [5]int) {
array[0] = 10
fmt.Println("i am modify,array values:", array) //i am modify,array values: [10 2 3 4 5]
}
切片
数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)来弥补数组的不足。
切片并不是数组或数组指针,它通过内部指针和相关属性引⽤数组⽚段,以实现变⻓⽅案。
slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。
map
Go语言中的map(映射、字典)是一种内置的数据结构,它是一个无序的key—value对的集合
package main
import (
"fmt"
)
// 在函数间传递映射并不会制造出该映射的一个副本,不是值传递,而是引用传递:
func deleteMap(m map[int]string, key int) {
delete(m, key)
for k, v := range m {
fmt.Printf("deleteMap---->%d ----> %s \n", k, v)
}
}
func main() {
var m1 map[int]string
fmt.Println(m1 == nil)
m2 := map[int]string{}
m3 := make(map[int]string)
fmt.Println(m2, m3)
//定义同时初始化
var m4 map[int]string = map[int]string{1: "mike", 2: "yoyo"}
fmt.Println(m4)
//赋值
var m5 map[int]string = map[int]string{1: "mike", 2: "yoyo"}
m5[1] = "xxx"
m5[2] = "lily"
fmt.Println("m5=", m5)
//遍历
for k, v := range m5 {
fmt.Printf("%d ----> %s \n", k, v)
}
//遍历
for k := range m5 {
fmt.Printf("%d ----> %s \n", k, m5[k])
}
//删除
//delete(m5, 2)
//for k := range m5 {
// fmt.Printf("%d ----> %s \n", k, m5[k])
//}
deleteMap(m5, 2)
for k := range m5 {
fmt.Printf("ater deleteMap------->%d ----> %s \n", k, m5[k])
}
}
结构体
有时我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别/年龄/地址等属性。显然单独定义以上变量比较繁琐,数据不便于管理。
结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合。每个数据称为结构体的成员
package main
import "fmt"
type Student struct {
id int
name string
sex byte
age int
addr string
}
//值传递,不改结构体内容
func printStudentValue(tmp Student) {
tmp.name = "值传递"
fmt.Println("printStudentValue temp=", tmp)
}
func printStudentPointer(p *Student) {
p.name = "引用传递"
fmt.Println("printStudentPointer p=", p)
}
func main() {
//普通变量
//顺序初始化,必须每个成员都初始化
var s1 Student = Student{1, "mike", 'm', 18, "sz"}
s2 := Student{2, "yoyo", 'f', 20, "sz"}
fmt.Println("s1=", s1)
fmt.Println("s2=", s2)
//指定初始化某个成员,没有初始化的成员未零值
s3 := Student{id: 2, name: "lili"}
fmt.Println("s3=", s3)
//指针变量
s4 := &Student{4, "coco", 'm', 3, "sh"}
fmt.Println("s4=", *s4)
//打印成员
s5 := Student{2, "yoyo", 'f', 20, "sz"}
fmt.Printf("id = %d, name= %s, sex=%c, age=%d ,addr=%s\n", s5.id, s5.name, s5.sex, s5.age, s5.addr)
//成员变量赋值
var s6 Student
s6.id = 2
s6.name = "yoyo"
s6.sex = 'f'
s6.age = 16
s6.addr = "guangzhou"
fmt.Println("s6=", s6)
//指针变量
s7 := new(Student)
s7.id = 3
s7.name = "xxx"
fmt.Println("s7=", s7)
//普通变量和指针变量类型打印
var s8 Student = Student{4, "uuu", 'm', 18, "sz"}
fmt.Printf("s8= %v , &s8 = %v\n", s8, &s8)
//指针变量赋值
var s9 *Student = &s8
s9.id = 10
(*s9).name = "zzz"
fmt.Println(s9, *s9, s8)
//结构体比较
fmt.Println("s1 == s2", s1 == s2)
//值传递
var s10 Student = Student{4, "uuu", 'm', 18, "sz"}
fmt.Println("before printStudentValue s10=", s10)
printStudentValue(s10)
fmt.Println("after printStudentValue s10=", s10)
//引用类型传递
var s11 Student = Student{4, "uuu", 'm', 18, "sz"}
fmt.Println("before printStudentPointer s10=", s11)
printStudentPointer(&s11)
fmt.Println("after printStudentPointer s10=", s11)
}
可见性
Go语言对关键字的增加非常吝啬,其中没有private、 protected、 public这样的关键字。
要使某个符号对其他包(package)可见(即可以访问),需要将该符号定义为以大写字母
开头。
函数
函数可以让我们将一个语句序列打包为一个单元,然后可以从程序中其它地方多次调用。函数的机制可以让我们将一个大的工作分解为小的任务,这样的小任务可以让不同程序员在不同时间、不同地方独立完成。一个函数同时对用户隐藏了其实现细节
函数声明
函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。
func name(parameter-list) (result-list) {
body
}
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func sub(x, y int) (z int) {
z = x - y
return z
}
func first(x int, _ int) int {
return x
}
func zero1(int, int) int {
return 0
}
func main() {
var addResult = add(3, 5)
fmt.Printf("%T\n", add) //func(int, int) int
fmt.Printf("%T\n", sub) //func(int, int) int
fmt.Printf("%T\n", first) //func(int, int) int
fmt.Printf("%T\n", zero1) //func(int, int) int
fmt.Printf("%d\n", addResult)
}
- 实参通过值的方式传递,因此函数的形参是实参的拷贝。对形参进行修改不会影响实参。但是,如果实参包括引用类型,如指针,slice(切片)、map、function、channel等类型,实参可能会由于函数的间接引用被修改。