GO语言学习笔记(4)| 青训营笔记

67 阅读5分钟

[ go 与 golang | 青训营笔记]

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天, 在学习了go的相关基础知识以后,可以说是初步的了解了go,我在这过程中也记录了一些自己的学习经验以及心得,与大家分享一下。

16. map

声明

map是key-value形式

它的key只能是基本数据类型

// 定义map
var m map[string]string
// 创建空间
m = make(map[string]string, 2) // size可以不写,默认为1

m["name"] = "张三"
m["age"] = "21"
m["addr"] = "湖南长沙"

fmt.Println(m)

简写

m2 := map[string]string{
  "name": "张三",
  "age": "12",
}

增加

通过map[key] = xxx

查找

通过双赋值检测某个key是否存在

v, ok := m2["name"]
if ok {
   // 如果存在,ok就为true
   fmt.Printf("v = %v", v)
}else{
   fmt.Printf("v不存在")
}

删除

delete(map, key) // 删除单个元素


遍历

map只有len,没有cap

len一个map,得到的就是key的个数

只有for range一种遍历方式

for key, value := range m{
  fmt.Printf("key=%v,value=%v\n", key, value)
}

切片中的元素为map类型

var mapSlice = make([]map[string]string, 3)
for index, value := range mapSlice {
    fmt.Printf("index:%d value:%v\n", index, value)
}
fmt.Println("初始化元素:")
// 对切片中的map元素进行初始化
mapSlice[0] = make(map[string]string)
mapSlice[0]["name"] = "小明"
mapSlice[0]["gender"] = "男"
mapSlice[0]["address"] = "长沙"
for index, value := range mapSlice {
    fmt.Printf("index:%d value:%v\n", index, value)
}

map中的值为切片类型

m := make(map[string][]string)
fmt.Println(m)
val := []string{"北京", "上海"}
m["中国"] = val
fmt.Println(m)
m["中国"] = append(m["中国"], "广州", "深圳")
fmt.Println(m)

17. 自定义数据类型

自定义数据类型

假如我想用4位数字表示消息的类型

也用4为数字表示异常的返回值

如果用uint16来表示,就容易搞混

所以就可以自定义一个数据类型

type msgType uint16

var textMes msgType = 1000
// 混用需要类型转换
var u1001 uint16 = 1001
var imageMes msgType = msgType(u1001)

fmt.Printf("textMes=%v, type of is %T\n", textMes, textMes)
fmt.Printf("imageMes =%v, type of is %T\n", imageMes, imageMes )

这个msgType 已经和uint16是属于不同的类型了

如果需要将uint16的变量赋值给msgType 的变量,则需要进行类型转换

类型别名

byte是uint8的别名

rune是int32的别名

type msgType = uint16
var textMes msgType = 1000
// 混用需要类型转换
var u1001 uint16 = 1001
var imageMes msgType = u1001

fmt.Printf("textMes=%v, type of is %T\n", textMes, textMes)
fmt.Printf("imageMes =%v, type of is %T\n", imageMes, imageMes)

类型别名就相当于是将uint16起了一个别的名字

赋值的时候也不用类型转换

18. 结构体

初识结构体

由一组字段构成的一种自定义数据类型

type User struct {
  Name string
  Id uint32
}

var u1 User = User{
  Name: "张三",
}
u1.Id = 10000

结构体字段

结构体可以没有字段

结构体字段通过.访问

继承

package main

import "fmt"

type User struct {
  Name     string
  Age      int
  password string
}

type Account struct {
  User
  money float32
  Name  string
}

func main() {
  var ac Account = Account{
    money: 21.9,
    User: User{
      Name:     "王五",
      Age:      21,
      password: "978345",
    },
    Name: "账户1",
  }
  fmt.Printf("ac %#v, %T\n", ac, ac)
  var u1 = User{
    Name:     "lisa",
    Age:      22,
    password: "1233fg",
  }
  var ac1 Account = Account{
    money: 21.9,
    User:  u1,
  }
  fmt.Printf("ac1 %#v, %T\n", ac1, ac1)

  fmt.Println(ac.money)
  fmt.Println(ac.Name)
  fmt.Println(ac.User.Name)
  fmt.Println(ac.password)
}

方法

package main

import "fmt"

type User struct {
  Name     string
  Age      int
  password string
}

func (u User) PrintName() string {
  u.Name = "张三"
  fmt.Println("printName方法: ", u)
  fmt.Printf("printName方法内部:%p \n", &u)
  return u.Name
}


func main() {
  user := User{"王二麻子", 23, "xsdfe23"}
  fmt.Printf("main: %p\n", &user)
  name := user.PrintName() // 是值传递,
  fmt.Println(name, user)
}

结构体指针

type User struct {
  Name string
  Id   uint16
}

var u User = User{
  Name: "zhangsan",
}
u.Id = 20
fmt.Println(u)
var u2 *User = &User{
  Name: "李四",
}
u2.Id = 21
fmt.Println(u2)

fmt.Printf("u = %+v, type of %T\n", u, u)
fmt.Printf("u2 = %+v, type of %T\n", u2, u2)CopyErrorOK!

继承

type User struct {
  Name string
  Id   uint16
}

type Account struct {
  User
  password string
}

type Contact struct {
  *User
  Remark string
}

// 实例化账户
var a1 = Account{
  User: User{
    Name: "张三",
    Id:   1,
  },
  password: "666",
}
var c1 *Contact = &Contact{
  User:   &a1.User,
  Remark: "王麻子",
}
// 没有重复字段就可以这样简写
c1.Name = "王五" // 等效于  c1.User.Name = "王五"

fmt.Printf("a1 = %+v\n", a1)

结构体标签

type User struct {
  Name string `json:"name"`
  Id   uint16 `json:"id"`
}

这样写好之后,结构体进行json转换的时候,Name就会自动变为name

package main

import (
  "encoding/json"
  "fmt"
)

type Article struct {
  Title     string `json:"title"`
  Desc      string `json:"desc"`
  Content   string `json:"content"`
  Username  string `json:"-"` // - 也不参与序列化
  LookCount int    `json:"look_count"`
  Free      bool   `json:"free"`
  password  string // 小写字母开头的不会参与序列化
}

func main() {
  article := Article{
    Title:     "golang文档",
    Desc:      "golang零基础入门,四小时转岗golang开发",
    Content:   "golang零基础入门,四小时转岗golang开发",
    Username:  "fengfeng",
    LookCount: 1024,
    password:  "ksd8%38",
    Free:      true,
  }

  // 结构体转json
  jsonData, err := json.Marshal(article)
  if err != nil {
    fmt.Println(err)
    return
  }
  jsonStr := string(jsonData)
  fmt.Println(jsonStr)

}

方法

和函数没什么区别

只是多了一个形参,是和结构体绑定在一起的

package main

import "fmt"

type User struct {
  Name string `json:"name"`
  Id   uint16 `json:"id"`
}

func (u User) PrintName() string {
  return u.Name
}

func main() {
  u := User{
    Name: "张三",
    Id:   1001,
  }
  fmt.Println(u.PrintName())
}

我们都知道golang的函数都是值传递

所以如果在方法中修改结构体的值

相当于修改的是结构体的副本

type User struct {
  Name string `json:"name"`
  Id   uint16 `json:"id"`
}

func (u User) SetName(name string) {
  u.Name = name
  fmt.Printf("setName修改之后:u=%+v\n", u)
}

func main() {
  u := User{
    Name: "张三",
    Id:   1001,
  }
  u.SetName("李四")
  fmt.Printf("setName运行完之后,u=%+v\n", u)
}

如果需要修改原结构体,那么需要传递的是结构体的指针

type User struct {
  Name string `json:"name"`
  Id   uint16 `json:"id"`
}

func (u *User) SetName(name string) {
  (*u).Name = name
  // 也可这样简写
  //u.Name = name
  fmt.Printf("setName修改之后:u=%+v\n", *u)
}

func main() {
  u := User{
    Name: "张三",
    Id:   1001,
  }
  u.SetName("李四")
  fmt.Printf("setName运行完之后,u=%+v\n", u)
}