变量
变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念。通过变量名访问变量中的数据Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。声明变量的一般形式是使用 var 关键字:例子:常规定义: var 变量名称 type自动推导: 变量名称 := (数据函数中使用)组合:var (a,b stringc boold int)var e,f = 123, "1234"函数中使用:g, h := 123, "hello"
基础数据类型
int,bool,string,bytes
派生据类型
一维数组
// 一维数组// 输出数据类型var names [1]stringfmt.Printf("%T\n", names)// 实例 使用... 自动推导后面的数据得到数组长度name := [...]string{"1", "2", "123", "3", "4", "5"}fmt.Printf("%T", name)fmt.Println(name)// 取值fmt.Println("切片的值为:", name[2])// 对指定位置的数据进行初始化 如下对长度为"3,1,4" 位置的数据进行修改passwd := [10]int{3: 1111, 1: 222, 4: 333}fmt.Println("访问和修改,长度为3的值:", passwd[3])// 获取数组的长度 长度为10fmt.Println("数组长度:", len(passwd))// 数组切片groups := [...]string{"python", "golang", "java", "C#", "groovy"}fmt.Println(groups[2:3]) // [开始:结束]// 遍历数组for i := 0; i < len(groups); i++ {fmt.Printf("第[%d]位数: %s\n", i, groups[i])}// 第二种遍历for i, v := range groups {fmt.Printf("[%d]: %s\n", i, v)}
多维数组
// 多维数组// 多为数组的长度只有一维可以自动推导,二维必须定义长度langes1 := [...][3]string{{"golang", "python", "groovy"}, {"java", "golang", "C++"}}langes2 := [3][3]string{{"windows项目", "shell", "groovy"}, {"java", "golang", "C++"}}langes3 := [3][3]string{0: {"windows项目", "shell", "groovy"}, 2: {"java", "golang", "C++"}}langes4 := [4][3]string{0: {0: "windows项目", 2: "shell", 1: "groovy"}, 1: {"java", "golang", "C++"}, 3: {"php", "javascriptr", "html"}}// 输出类型fmt.Printf("数组: \n%T\n%T\n%T\n%T\n", langes1, langes2, langes3, langes4)// 输出值fmt.Printf("%q\n", langes1)// 多为数组访问devops := langes1[0][0:2]fmt.Printf("运维开发需要掌握的语言:%s\n", devops)dev := langes2[1][0:3] // 一般结束位都需要按照下标+1fmt.Printf("开发需要掌握的语言:%s\n", dev)// 多维数组修改fmt.Printf("更正前- 运维开发需要掌握的语言为:%s\n", langes1[0])langes1[0][2] = "shell"fmt.Printf("更正后- 运维开发需要掌握的语言为:%s\n", langes1[0])fmt.Println("----------------------")fmt.Printf("更正前- 运维开发需要掌握的技能为:%s\n", langes2[0])langes2[0] = [3]string{"linux", "database", "CICD"}fmt.Printf("更正后- 运维开发需要掌握的技能为:%s\n", langes2[0])// 多维数组遍历// langes3 := [3][3]string{0: {"windows项目", "shell", "groovy"}, 2: {"java", "golang", "C++"}}for i, line := range langes3 {// pkg_fmt.Printf("第一次遍历:%s\n", line)for ii, vv := range line {// pkg_fmt.Printf("第二次遍历: %s\n", vv)fmt.Printf("langes3数组中的值为:[%d %d %s]\n", i, ii, vv) // 此处需要多注意}}// 多为数组遍历第二遍测试for i, line := range langes1 {// pkg_fmt.Printf("第一次遍历:%s\n", line)for ii, vv := range line {// pkg_fmt.Printf("第二次遍历: %s\n", vv)fmt.Printf("langes1数组中的值为:[%d %d %s]\n", i, ii, vv) // 此处需要多注意}}
切片
// 切片 切片是长度可变的数组,数组在定义好之后长度不可变// 声明切片 nil切片var slice1 []stringfmt.Printf("%T,%t,%v\n", slice1, slice1 == nil, slice1)// 初始化 使用make函数初始化切片slice2 := make([]string, 10)slice3 := []string{"1", "3", "2"}arrs := [...][3]string{{"golang", "python", "groovy"}, {"java", "golang", "C++"}}// 切片类型fmt.Printf("切片:%q 类型: %T\n", slice3, slice3)// 切片类型fmt.Printf("切片:%T, 无固定长度\n", slice2)// 数组类型fmt.Printf("数组:%T, 必须有长度\n", arrs)/*切片和数组的区别:数组是长度固定的元素序列 切片:[]string切片是长度可变的元素序列 数组:[2][3]string*//*切片初始化后才能用 否则无法使用make([]数据类型, 长度, 步长)*/stu := make([]string, 3, 5)fmt.Printf("步长: %d\n长度: %d\n", len(stu), cap(stu))fmt.Printf("%q,%q\n", stu[0], stu[1:5])// 切片定义stu2 := []string{"golang", "java", "python", "C#", "C++"}// 修改切片中的值stu[0] = "golang"stu[1] = "python"fmt.Printf("%q,%q\n", stu[0], stu[1])fmt.Printf("%T : %q\n", stu2, stu2)// 切片遍历第一种方式for index, value := range stu2 {fmt.Printf("切片第一种遍历: %d %s\n", index, value)}// 切片遍历第二种方式for i := 0; i < len(stu2); i++ {fmt.Printf("切片第二种遍历: %s\n", stu2[i])}// 切片添加元素 appendstu2 = append(stu2, "shell")fmt.Println(stu2)// 可以将string拼接到byte切片slice := make([]byte, 10)var a string = "Hi "var b string = "YY"slice = append([]byte(a), b...)fmt.Println("切片追加,解包的方式: ", string(slice))/*切片删除元素stu2[start:end] stu2中,从start开始到end-1所有元素组成的切片以索引进行删除*/stu2 = stu2[0:4]fmt.Println(stu2)// 删除第一个元素,删除最后一个元素// 切片定义stu3 := []string{"golang", "java", "python", "C#", "C++"}stu4 := stu3[1:len(stu3)]fmt.Println(stu3)fmt.Printf("stu4: %s\n", stu4)stu5 := stu3[0:len(stu3)]fmt.Printf("stu5: %s\n", stu5)// 删除中间一个数据 删除3nums1 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}// copy(dst,src) src > dstnums2 := []int{10, 11, 12, 13, 15, 15, 16}copy(nums1, nums2) // 按照索引进行复制对应起来fmt.Println(nums1, nums2)
映射
// 映射map 类似py字典// 定义map 第一种// 声明定义var Iaas map[string]stringIaas = map[string]string{"name": "alinx", "age": "28", "site": "cn"}/*直接使用make进行初始化创建map定义map 第二种*/man := make(map[string]string)fmt.Printf("%T,%q\n%T\n", Iaas, Iaas, man)// 定义map 第三种wom := map[string]string{}fmt.Printf("%T\n", wom)// 操作maplanges := map[string]string{"dev": "golang,java,,,,python", "ops": "shell,python,golang", "devops": "golang,shell"}fmt.Println(strings.Split(langes["dev"], ",")) // 数据分割fmt.Printf("长度: %d\n", len(langes))// map 获取值dev, ok := langes["dev"]fmt.Printf("map取值:\n 存在吗:%t\n 取出值:%v\n", ok, dev)// 修改值langes["ops"] = "java,C++"fmt.Printf("修改后的值:%s\n", langes)// 删除值delete(langes, "dev")fmt.Printf("删除后的值:%s\n", langes)// 遍历map(映射)for k, v := range langes {fmt.Printf("遍历map数据: %s %s\n", k, v)}
列表
package mainimport ("container/list""fmt")func main() {// 列表的定义var name list.List // 生成列表类型names := list.New() // 返回列表对应的指针fmt.Printf("%T,%#v\n", name,name)fmt.Printf("%T,%#v\n", names,names)for i := 1; i < 10; i++ {names.PushBack(i)}//插入值first := names.PushFront(0)// 删除值names.Remove(first)// 遍历值// Front函数获取列表的头元素 Next() 函数依次往下遍历for l := names.Front(); l != nil ; l = l.Next() {fmt.Print(l.Value, " ")}}
结构体
认识结构体
package mainimport "fmt"/* 结构体是一些列属性组成的复合数据类型,每个属性都具有名称语法:type TypeName formatter*/// 基于现有数据类型定义结构体type Counters intvar num int = 10// 基于现有类型定义type User map[string]string// 别名类型定义type Counter = int// 函数类型定义type Callback func() errorfunc main() {var counter Counterfmt.Printf("%T,%v\n", counter, counter)// var user User// user["id"] = "1" //无法直接赋值,需要使用make初始化之后才能使用var user User = make(User)user["id"] = "1"fmt.Printf("%T,%v\n", user, user)// 函数类型使用callbacks := map[string]Callback{}callbacks["users"] = func() error {fmt.Println("add")return nil}// 调用 函数类型结构体callbacks["users"]()// 特殊类型 别名var (r runeb byte)fmt.Printf("%T, %T", r, b)}
结构体组合
package mainimport ("fmt""time")// 组合类型结构体type User struct {// 定义结构体属性id intname stringaddr stringtel stringbirthday time.Time}func main() {// 定义结构体类型的变量var user User// 零值是由各元素的零值组成的一个结构体的变量fmt.Printf("%T,%#v\n", user, user)// 字面量初始化方式( 必须严格按照结构体定义顺序指定 ,且每一个属性都必须指定值)user = User{10, "alinx", "xxxx", "138", time.Now()}fmt.Printf("%T,%#v\n", user, user)// 按照属性名定义字面量,可以无序user = User{id: 1, name: "alinxsss", addr: "999", tel: "112123123"}fmt.Printf("%T, %#v\n", user, user)// 属性访问和修改// 访问fmt.Println(user.id)fmt.Println(user.name)fmt.Println(user.tel)// 修改user.id = 9999user.name = "good"user.birthday = time.Now()fmt.Printf("%T, %#v\n", user, user)}
结构体指针
package mainimport ("fmt""time")// 面向对象: 封装,继承,多态// 结构体类似与面向对象中的类定义/*结构体 => 类构造函数 => 创建类对于的实例方法*/type User struct {id intname stringtel stringaddr stringbirthday time.Time}// New函数定义 ,定义一个结构体func NewUser(id int, name, tel, addr string, birthday time.Time) User {return User{id, name, tel, addr, birthday}}// 指针类使用方式// func NewUser(id int, name, tel, addr string, birthday time.Time) *User {// return &User{id, name, tel, addr, birthday}// }func main() {// 结构体指针// 指针类型,直接取地址 &引用// var user *User = &User{id: 999, name: "alinx"}// *User 可以省略var user = &User{id: 888, name: "Love"}fmt.Printf("%T\n%#v", user, user)// 结构体 new函数初始化user = new(User)fmt.Printf("%T\n,%#v\n", user, user)u2 := new(User)fmt.Printf("%T,\n%#v\n", u2, u2)// 属性访问fmt.Println(u2.name)u2.id = 9999999999u2.name = "gooooood"fmt.Println(u2.name, u2.id)u3 := NewUser(1, "2222", "", "", time.Now())fmt.Printf("%T,%#v\n", u3, u3)}
匿名结构体
package mainimport ("fmt""time")func main() {c := func() {fmt.Println("匿名函数")}fmt.Printf("%T\n", c)// 匿名结构体, 一般用于配置类var user struct {id intname stringtel stringaddr stringbirthday time.Time}fmt.Printf("%T,%#v\n", user, user)user.id = 123user.name = "sadfasdf"fmt.Printf("%T,%#v\n", user, user)// 初始化,零值,字面量 使用user = struct {id intname stringtel stringaddr stringbirthday time.Time}{111, "alinx", "123123", "sdddd", time.Now()} // 结构体类型fmt.Printf("%T,%#v\n", user, user)// 定义时 就进行初始化var u2 struct {id intname string} = struct {id intname string}{123, "alinx"}fmt.Printf("%T,%#v\n", u2, u2)// 简写 指针加&即可 , 一般作为数据传递var u2 = struct {id intname string}{id: 111, name: "ddd"}fmt.Printf("%T,%#v\n", u2, u2)var u2 = &struct {id intname string}{id: 111, name: "ddd"}fmt.Printf("%T,%#v\n", u2, u2)}
组合结构体
package mainimport ("fmt""time")type Addr struct {province stringstreet stringno string}type Tel struct {prefix stringnumber string}// 命名组合(嵌入)type User struct {id intname stringaddr *Addr // 组合Addr结构体tel *Tel // 组合Tel结构体birthday time.Time}func main() {// 初始化使用var user User = User{id: 1, name: "alinx", addr: &Addr{}, tel: &Tel{}, birthday: time.Now()}fmt.Printf("%T,%#v", user, user)// 写入 和读取 如果是指针就加指针进行调用即可 &Addrvar users User = User{addr: &Addr{province: "贵州省"}}// 访问fmt.Println(users.addr.province)// pkg_fmt.Printf("%T,%#v", users, users)}
匿名组合结构体
package mainimport ("fmt""time")type Addr struct {province stringstreet stringno string}type Tel struct {prefix stringnumber string}// 匿名组合结构体type User struct {id intname stringAddr // 只指定类型,会自动定义属性名为类型名Tel // 只指定类型birthday time.Time}func main() {// 初始化使用var user User = User{Addr: Addr{province: "guizhou"}}fmt.Printf("%T,%#v\n", user, user)fmt.Println(user.province)user.province = "广东省"fmt.Println(user.province)// 访问和修改user.Addr.province = "贵州省"fmt.Println(user.Addr.province)fmt.Println(user)}
使用实例
package mainimport ("fmt""time")type Users struct { //值类型id intname stringaddr stringtel stringbirthday time.Timecreated_at time.Timeupdated_at time.Timeflag boolstatus intdeleted_at *time.Time}func main() {// 指针var t *time.Timefmt.Println(t) // 零值nil// 定义User类型的变量var u Users // 所有属性的零值组成的一个Users类型变量值fmt.Printf("%T\n", u)fmt.Printf("%v\n", u) // 拿到结构体初始化fmt.Printf("%#v\n", u)// 赋值 按照顺序 需要给所有属性都进行赋值u = Users{1, "alinx", "贵州", "188xxxxxx", time.Now(), time.Now(), time.Now(), false, 0, nil}fmt.Printf("%#v\n", u)// 指定名称进行赋值u = Users{id: 2, name: "alinx"}fmt.Printf("%#v\n", u)// 属性访问fmt.Println(u.id)fmt.Println(u.name)fmt.Println(u.birthday.Clock())// 值类型 修改u.id = 999999fmt.Println(u.id)// 指针类型var u3 *Usersfmt.Printf("%T, %v\n", u3, u3)// 指针赋值u3 = &ufmt.Println("%#v\n", u3)// new 申请空间并对元素使用0值进行初始化,取地址,赋值var u4 *Users = new(Users)var u5 *Users = &Users{} // 类似newfmt.Printf("%#v\n", u4)fmt.Printf("%#v\n", u5) // 初始化值取0值}
接口
接口是一个实现了功能的组合调用对象
接口是对行为的抽象 => 实现行为的对象定义接口: 定义的一些函数签名: 参数列表,返回值列表关键字: interfacetype TypeName Formattertype interfaceName interface {方法签名}
接口使用实例
package mainimport "fmt"// 接口定义type User struct {Id intName string}// 定义接口 Persistent/* 行为:Save保存User切片*/type Persistent interface {// 方法名称 返回值类型 接口中所定义的方法,需要有确切的实现,否则异常Save([]User,string) errorLoad(string) ([]User,error)}// 实现原则: 定义了GObPersustent 所有接口 就叫GObPersustent实现了Persistent接口// 第一个结构体实现 Persistent接口type GObPersustent struct {}// 基于GObPersustent结构体 实现Save方法func (p GObPersustent) Save(users []User,path string) error {fmt.Printf("\ngob persistent save")return nil}// 基于GObPersustent结构体 实现Load方法func (p GObPersustent) Load(path string) ([]User,error) {fmt.Printf("\ngob persistent load")return nil,nil}// 第二个结构体实现 Persistent接口type CsvPersistent struct{}// 基于CsvPersistent结构体 实现Save方法func (p CsvPersistent) Save(users []User,path string) error {fmt.Println("csv persistent save")return nil}// 基于CsvPersistent结构体 实现Load方法func (p CsvPersistent) Load(path string) ([]User, error) {fmt.Println("csv persistent load")return nil,nil}// 此处使用接口作为类型 对接起来调用测试func call(persistent Persistent) {fmt.Println("\ncall:")persistent.Save(nil,"")persistent.Load(":")}// 调用CsvPersistent结构体实现了 Persistent 接口的方法func Csv() {var persistent Persistentfmt.Printf("%T,%#v\n", persistent, persistent)persistent = CsvPersistent{}persistent.Load("")persistent.Save(nil,"")/*接口 不能直接通过接口类型进行初始化对象结构体使用实现行为(实现接口的所有方法,某个对象的类型定义了接口中所有的方法)的对象*/}// 调用GObPersustent结构体实现了 Persistent 接口的方法func GOb() {var persistent Persistentfmt.Printf("%T,%#v\n", persistent, persistent)persistent = GObPersustent{}persistent.Load("")persistent.Save(nil,"")/*接口 不能直接通过接口类型进行初始化对象结构体使用实现行为(实现接口的所有方法,某个对象的类型定义了接口中所有的方法)的对象*/}func main() {// 调用 默认是值类型调用Csv()GOb()/*接口 不能直接通过接口类型进行初始化对象*/// 在类型上 值类型会自动 生成指针类型 指针接收者无法生成值接收者var persistent Persistentfmt.Printf("%T,%#v\n", persistent, persistent)call(GObPersustent{})call(CsvPersistent{})/*定义类型与接口是否实现 无语法上直接关联鸭子类型: 你怎么判断一个动物是否是一个鸭子根据行为判断: 游泳,嘎嘎叫 都是鸭子总结: 根据以上知识 只要结构体实现了接口中定义的方法 那就是接口类型,就能赋值进行调用*/// 指针对象 自动生成的指针类型调用persistent = new(CsvPersistent)fmt.Println("指针类型:\n\n%T,%#v\n", persistent,persistent)persistent.Load("")persistent.Save(nil,"")call(&CsvPersistent{})call(&GObPersustent{})}
