[js go]映射与结构体

769 阅读4分钟

映射map

在go中, map是固定类型的键值对的集合, 区别于js中的map

声明map

	var mapList1 map[string]int  // 声明
	fmt.Println(mapList1)        // map[]
	fmt.Println(mapList1 == nil) // true
	// mapList1["width"] = 100 // panic: assignment to entry in nil map 需要make以后才能使用

开辟内存空间并初始化

	mapList2 := make(map[string]int, 2) // 使用全局make函数开辟内存空间
	fmt.Println(mapList2)        // map
	fmt.Println(mapList2 == nil) // false
	fmt.Println(len(mapList2))   // 0
	mapList2["width"] = 100
	mapList2["height"] = 100
	mapList2["weight"] = 100
	fmt.Println(len(mapList2)) // 3
	fmt.Println(mapList2)      // map[height:100 weight:100 width:100]

查key的value

	value, ok := mapList2["weight"] // 取值
	if ok {
		fmt.Println("value: ", value) // value:  100
	}

删除key

	delete(mapList2, "weight") // 删除键
	fmt.Println(mapList2)      // map[height:100 width:100]
	_, ok = mapList2["weight"]
	if !ok {
		fmt.Println("weight has been deleted") // weight has been deleted
		fmt.Println("len(mapList2): ", len(mapList2)) // len(mapList2):  2
	}

用map解决两数之和

func twoSum(nums []int, target int) []int {
  var res []int
  memory := make(map[int]int)
  for index, value := range nums {
    memory[value] = index 
  }
  for index, value := range nums {
    _index, ok := memory[target - value]
    if ok && _index != index {
      res = append(res, index, _index)
      break
    }
  }
  return res
}

结构体struct

在go中, 结构体是开发者自定义的新类型, 可以是不同类型的键值对的集合

类型定义与类型别名

	type MyIntA int   // 类型定义, 定义新类型
	type MyIntB = int // 类型别名 alias, 没有定义新类型
	var myIntA MyIntA
	var myIntB MyIntB
	fmt.Printf("%T \n", myIntA) // main.MyIntA
	fmt.Printf("%T \n", myIntB) // int

定义结构体

// 结构体
type Pig struct {
	name, color string // 相同类型的属性可以合并在同一行
	age         int
	bool        // 匿名属性
}

声明实例化

	var p1 Pig               // 声明结构体的实例
	fmt.Printf("%T \n", p1)  // main.Pig 类型
	fmt.Println(p1)          // {  0 false}  各属性默认零值
	fmt.Printf("%#v \n", p1) // main.Pig{name:"", color:"", age:0, bool:false}  查看实例的详细信息
	p1.name = "小猪佩奇"
	p1.color = "pink"
	p1.age = 7
	p1.bool = false          // 匿名属性赋值
	fmt.Println(p1)          // {Pappa Pig pink 7 false}
	fmt.Printf("%v \n", p1)  // {Pappa Pig pink 7 false}
	fmt.Printf("%#v \n", p1) // main.Pig{name:"Pappa Pig", color:"pink", age:7, bool:false}

实例的内存分配

	fmt.Printf("%p \n", &p1)       // 0xc000078180  查看实例的内存地址
	fmt.Printf("%p \n", &p1.name)  // 0xc000078180  查看实例的name属性内存地址
	fmt.Printf("%p \n", &p1.color) // 0xc000078190  查看实例的color属性内存地址
	fmt.Printf("%p \n", &p1.age)   // 0xc0000781a0  查看实例的age属性内存地址
	fmt.Printf("%p \n", &p1.bool)  // 0xc0000781a8  查看实例的bool属性的内存地址

new实例化

使用全局new函数实例化, 类似js中的new关键字

	p2 := new(Pig)
	fmt.Printf("%T \n", p2)  // *main.Pig main包里的Pig类型的指针
	fmt.Printf("%p \n", p2)  // 0xc0000782d0  查看指针的内存地址
	fmt.Printf("%p \n", &p2) // 0xc00000e030  查看指针指向的实例的内存地址
	p2.name = "George"       // 可以通过指针直接给实例赋值
	p2.color = "pink"
	p2.age = 5
	p2.bool = true

取结构体地址实例化

	p3 := &Pig{}
	fmt.Printf("%T \n", p3) // *main.Pig main包里的Pig类型的指针

属性赋值实例化

	// 使用键值对实例化的同时初始化
	p4 := Pig{
		name: "p4", // 注意属性后面的逗号
		age:  5,
		bool: false, // 匿名属性初始化
	}
	fmt.Printf("%T \n", p4)  // main.Pig 类型
	fmt.Printf("%#v \n", p4) // main.Pig{name:"p4", color:"", age:5, bool:false} 没初始化的属性为零值

结构体取地址并初始化

	// 使用值实例化的同时初始化并取地址, 按顺序挨个给属性初始化
	p5 := &Pig{
		"p5",
		"pink",
		5,
		true, // 注意最后一个属性的后面也要有逗号
	}
	fmt.Printf("%T \n", p5)  // *main.Pig
	fmt.Printf("%#v \n", p5) // &main.Pig{name:"p5", color:"pink", age:5, bool:true}

空结构体

	p6 := Pig{}
	fmt.Printf("%T \n", p6)  // main.Pig
	fmt.Printf("%#v \n", p6) // main.Pig{name:"", color:"", age:0, bool:false}

构造函数

func newPig(name, color string, age int, gender bool) *Pig {
	return &Pig{
		name:  name,
		color: color,
		age:   age,
		bool:  gender,
	}
}

// 使用构造函数生成实例
p7 := newPig("p7", "pink", 7, true)
fmt.Printf("%T \n", p7)  // *main.Pig
fmt.Printf("%#v \n", p7) // &main.Pig{name:"p7", color:"pink", age:7, bool:true}

添加实例方法

// 添加方法, 形参为Pig首字母小写p, 类似js中的this, 指向当前实例
func (p Pig) say(hobby string) (mood string, isSmile bool) {
	fmt.Printf("我是%s, 我喜欢%s儿~ \n", p.name, hobby)
	return "happy", true
}

// 调用方法
mood, isSmile := p1.say("踩泥坑")                        // 我是小猪佩奇, 我喜欢踩泥坑儿~
fmt.Printf("mood: %s, isSmile: %v \n", mood, isSmile) // mood: happy, isSmile: true

值类型接收者和指针类型接收者

// 值类型接收者
func (p Pig) growUpValue(year int) {
	p.age += year
}

// 指针类型接收者
func (p *Pig) growUpPointer(year int) {
	p.age += year
}

fmt.Printf("age: %v \n", p1.age) // 7
p1.growUpValue(1)
fmt.Printf("age: %v \n", p1.age) // 7 只改变了值副本的age属性值
p1.growUpPointer(1)
fmt.Printf("age: %v \n", p1.age) // 8 改变了引用的age属性值

嵌套结构体与继承

// 嵌套结构体
type PigWithSister struct {
	name   string
	sister Pig
	*Pig   // 匿名属性嵌套结构体指针
}

p8 := PigWithSister{
	name:   "乔治",
	sister: p1,
	Pig: &Pig{
		name: "乔治",
	},
}
fmt.Printf("%s的姐姐是%s\n", p8.name, p8.sister.name) // 乔治的姐姐是小猪佩奇~
p8.say("踩泥坑")                                     // 我是乔治, 我喜欢跳泥坑儿~  继承了Pig的say方法

tag、序列化与反序列化

type Dog struct {
	Kind  string `json:"kind"`
	name  string // 属性名首字母小写, 为本包私有, 不能被json包访问
	Smart bool
}

// 序列化与反序列化
d1 := Dog{
	name:  "wangwang",
	Kind:  "husky",
	Smart: true,
}
dataStr, err := json.Marshal(d1)
if (err == nil) {
	fmt.Printf("dataStr: %s \n", dataStr) // dataStr: {"kind":"husky","Smart":true}
	dataObj := &Dog{}
	err := json.Unmarshal([]byte(dataStr), dataObj)
	if (err == nil) {
		fmt.Printf("dataObj: %#v \n", dataObj) // dataObj: &main.Dog{Kind:"husky", name:"", Smart:true} name属性为零值
	}
}