map与结构体、函数与方法


map

  • java 的map,python 的dict;
  • var mapName map[int]string,声明完并没有分配内存空间;
  • key 的可用类型:bool,数字,string,指针,channel;只包含前面几个类型的接口,结构体,数组
  • key 通常为 int,string;value 通常为数字,string,map,结构体;
  • slice,map,function 不可以作为key;
  • 声明时初始化要注意最后一项的逗号不能丢;
  • map 元素的增删改查:增加、修改一个操作,key还没有就是新增,否则是修改操作;删除使用 delete(map, keyName)
    • delete 为内置函数,key 存在时就删除,不存在不会操作,也不报错;
    • 清空map:遍历key,逐个删除;或者 map = make(…) make一个新的空间,让原来的成为垃圾,被gc回收;
    • 查询: val, bool = map[key]; val 为返回的值; bool为是否返回,true/false
  • 获取长度:len(map)
  • 遍历:for-range

map 特点

  • map 在使用前要先使用make 函数创建空间;
  • map 的key-val 是无序的
  • key 不可以重复,如果遇到重复的后放入的val 替换先前的val;
  • val 可用重复

面向对象

  • golang 能支持面向对象编程的特性;
  • golang 没有类,使用结构体 struct 实现其他语言class 的功能;
  • golang 面向对象编程非常简洁,去掉了传统oop 语言的方法的重载,构造函数,析构函数,隐藏this指针等;
  • golang 仍然有面向对象编程的继承,封装和多态的特性;但是实现方式和其他语言不一样;
  • golang 继承没有 extends 关键字,继承时通过匿名字段来实现的;

结构体

  • type stu struct{ Name string age int // 小写结包外不可访问 School string }
  • var stu Stu = Stu{"脑斧", 18, "peking"}; // 必须按照顺序赋值
  • var s *Stu = new(Stu)
  • var s *Stu = &Stu{}
  • var s3 *Stu = &Stu{"脑斧", 18, "peking"}
  • var s3 = &Stu{"脑斧", 18, "peking"}; *Stu 省略掉

结构体之间的转换

  • 结构体时用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数、类型),进行强制转换:type(type_another)
  • 结构体进行 type 重新定义(相当于取别名), Golang 认为是新的数据类型,但是相互之间可用强制转换;

结构体传教示例时指定字段值

  • var stu Stu = Stu{"脑斧", 18, "peking"}; // 必须按照顺序赋值
  • 按照指定字段: var s3 *Stu = &Stu{Name: "脑斧", Age: 18}
  • 返回结构体的指针类型:var s3 *Stu = &Stu{"脑斧", 18, "peking"}

跨包创建结构体

  • 首字母大写,可以在其他包下访问
  • 如果结构体首字母小写,跨包访问需要使用方法进行暴露,类似工厂模式;

方法

  • 注意方法语义上就不同于函数;
  • 方法是作用在指定的数据类型上、和指定的主机类型绑定,自定义类型(type 别名)、结构体,都可以有方法,体现了go 语言的灵活性;
  • 方法声明和调用:
// 声明
type A struct{
	Num int
}

func (a A) aMethod() { // (a A) 体现方法 aMethod 和结构体A 的绑定关系
	fmt.Println(a.Num)
}

// 调用
var a A = A{18}
a.aMethod()
  • 结构体对象传入aMethod 方法中,是值传递,和函数参数传递机制一样;所以为了在方法中修改调用变量的属性方法一般这样声明;
package main

func (a *A) aMethod() { // (a A) 体现方法 aMethod 和结构体A 的绑定关系
fmt.Println(a.Num)
}
  • 注意方法/函数调用时 golang 取地址,解地址的简化写法;
  • Golang 中的方法作用在 指定的数据类型上,和指定的数据类型绑定,因此自定义类型,都可以有方法;int,float32 起别名后也可以有方法。
  • 方法的访问范围控制规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问。
  • 如果一个 结构体/类型 实现了 String() 方法,那么 fmt.Println 默认会调用这个变量的 String() 方法进行输出;

方法和函数的区别

  • 绑定类型:方法需要绑定指定的数据类型;函数不需要绑定数据类型;
  • 调用方式:函数:函数名(参数列表); 方法:具体的类型变量.方法名(参数列表);
  • 函数:参数类型是什么就要传入什么;
  • 方法:接收者为值类型,可以传入指针类型;接受者为指针类型可以传入值类型。简单说就是可以自动取地址和解地址。

代码

package main

import "fmt"
import "02_type/model"

func main(){
	fmt.Println("==>> 定义map;通过make 进行初始化,分配内存空间:")
	var a map[int]string
	// 10 表示可用存放10个键值对
	a = make(map[int]string, 10)
	fmt.Println("a=", a)

	fmt.Println("\n==>> 几种定义map的方式:")
	b := make(map[int]string)
	fmt.Println("b=", b, "b.len=", len(b))
	b[1] = "1"
	b[2] = "2"
	fmt.Println("b=", b, "b.len=", len(b))

	c := map[int]string{
		1:"1",
		2:"2", // 右大括号换行时,这个逗号不能省略
	}
	c[3] = "3"
	fmt.Println("c=", c)


	fmt.Println("\n==>> map增删改查:")
	fmt.Println("==>> 新增元素:")
	a[1] = "1"
	a[222] = "222"
	a[3] = "谁"
	fmt.Println("a=", a)
	fmt.Println("==>> map 修改元素:")
	a[3] = "go-java-c"
	fmt.Println("a[3] 修改后,a=", a)
	fmt.Println("==>> map 删除元素:")
	delete(a, 3)
	fmt.Println("a[3] 删除后,a=", a)
	delete(a, 4)
	fmt.Println("a[4](没有的key) 删除后,a=", a)
	val,found := a[4]
	fmt.Println("val=", val)
	fmt.Println("found=", found)

	fmt.Println("\n==>> 遍历c:", c)
	for k,v := range c {
		fmt.Printf("key:%v, val:%v\n", k, v)
	}

	fmt.Println("\n==>> map 的val为map:")
	d := make(map[string]map[int]string)
	fmt.Println(d)
	d["1"] = make(map[int]string)
	d["1"][2012500407] = "407"
	d["1"][2012500408] = "408"
	d["1"][2012500409] = "409"
	fmt.Println("d=", d)
	for key, val := range d {
		fmt.Println("key=", key)
		for stuNo, name := range val {
			fmt.Println("stuNo=", stuNo, "name=", name)
		}
	}

	fmt.Println("\n ==>> 结构体:")
	fmt.Println("\n ==>> ----------------几种不同的初始化,赋值方式-------------------")
	var s1 Stu
	fmt.Println("s1=", s1)
	s1.Name = "小脑斧"
	s1.age = 18
	s1.School = "清华大学"
	fmt.Println("字段赋值后:s1=", s1)
	fmt.Println("age=", s1.age)

	fmt.Println("==>> 声明时直接给属性赋值:")
	var stu Stu = Stu{"脑斧", 18, "peking"}
	fmt.Println("stu=", stu)

	fmt.Println("==>> 使用指针赋值:")
	var s *Stu = new(Stu)
	// go 默认解地址
	s.Name = "脑斧"
	(*s).age = 18
	fmt.Println("指针方式: s=", *s)

	fmt.Println("==>> & 取地址:")
	var s2 *Stu = &Stu{}
	s2.Name = "小脑斧"
	s2.School = "清华大学"
	fmt.Println("s2=", *s2)

	fmt.Println("==>> & 取地址,并初始化属性:")
	var s3 = &Stu{"脑斧", 18, "peking"}
	fmt.Println("s3=", *s3)

	fmt.Println("==.>> 两个结构体之间强制转换:")
	var stu2 Student
	var p Person
	stu2 = Student(p)
	fmt.Println("stu2 = Student(p): stu2=",stu2)

	fmt.Println("==>> 起别名:")
	var student Student = Student{10}
	var stuAlias StuAlias = StuAlias{20}
	// 报错: Cannot use 'stuAlias' (type StuAlias) as the type Student
	// student = stuAlias
	student = Student(stuAlias)
	fmt.Println("student=", student)
	fmt.Println("stuAlias=", stuAlias)
	fmt.Println("StuAlias-> Student: student=", student)

	fmt.Println("\n==>> 方法:")
	fmt.Println("==>> -----------------------------------")
	// 调用
	var aTest A = A{18}
	aTest.aMethod()

	fmt.Println("==>> 方法值传递测试:")
	fmt.Println("aTest.Num=", aTest.Num)
	aTest.numUpdate(20)
	fmt.Println("aTest.Num 更新后,并未改变:aTest=", aTest)


	fmt.Println("==>> 方法使用地址传递:")
	fmt.Println("aTest.Num=", aTest.Num)
	(&aTest).numUpdatePointer(19)
	fmt.Println("使用 &aTest调用 aTest.Num 更新后:aTest=", aTest)
	// go 默认会取地址传递地址;编译器进行了优化
	aTest.numUpdatePointer(20)
	fmt.Println("使用默认传地址: aTest.Num 更新后:aTest=", aTest)

	fmt.Println("\n==>> 基础数据类型别名绑定方法:")
	var i integer = 20
	i.printInt()

	fmt.Println("==>> 方法体内修改(i=18)后:")
	i.changeInt()
	fmt.Println("i=", i)

	fmt.Println("\n==>> 结构体实现 String() 方法:")
	human := Human{Name: "linux", Age: 18}
	fmt.Println("human=", human)
	fmt.Println("使用 &human 可以调用 String() 方法:\n &human=", &human)

	fmt.Println("\n==>> 跨包创建结构体测试:")
	modelStu := model.Student{Name: "脑斧", Age: 18}
	fmt.Println("modelStu=", modelStu)

	fmt.Println("==>> 跨包创建结构体, 首字母小写,使用方法暴露:")
	lowCaseModelStu := model.GetLowCaseStudent("小脑斧", 19)
	fmt.Println("lowCaseModelStu=", *lowCaseModelStu)
}
type Human struct {
	Name string
	Age int
}

func (h *Human) String() string{
	str := fmt.Sprintf("Name= %v, Age= %v", h.Name, h.Age)
	return str
}

type integer int

func (i integer) printInt(){
	fmt.Println("i= ", i)
}

func (i *integer) changeInt(){
	*i = 18
	fmt.Println("i= ", *i)
}

type A struct{
	Num int
}

func (a *A) numUpdatePointer(numNew int) {
	a.Num = numNew
}

func (a A) aMethod() {
	fmt.Println("A.num=",a.Num)
}


func (a A) numUpdate(numNew int) {
	a.Num = numNew
}

type StuAlias Student

type Student struct{
	Age int
}

type Person struct{
	Age int
}

type Stu struct{
	Name string
	age int // 小写则包外不可访问
	School string
}
  • model/Student.go
package model

type Student struct {
	Name string
	Age int
}

type lowCaseStudent struct {
	Name string
	Age int
}

func GetLowCaseStudent(name string, age int) *lowCaseStudent{
	return &lowCaseStudent{name, age}
}

运行结果

==>> 定义map;通过make 进行初始化,分配内存空间:
a= map[]

==>> 几种定义map的方式:
b= map[] b.len= 0
b= map[1:1 2:2] b.len= 2
c= map[1:1 2:2 3:3]

==>> map增删改查:
==>> 新增元素:
a= map[1:1 3:谁 222:222]
==>> map 修改元素:
a[3] 修改后,a= map[1:1 3:go-java-c 222:222]
==>> map 删除元素:
a[3] 删除后,a= map[1:1 222:222]
a[4](没有的key) 删除后,a= map[1:1 222:222]
val= 
found= false

==>> 遍历c: map[1:1 2:2 3:3]
key:3, val:3
key:1, val:1
key:2, val:2

==>> map 的val为map:
map[]
d= map[1:map[2012500407:407 2012500408:408 2012500409:409]]
key= 1
stuNo= 2012500407 name= 407
stuNo= 2012500408 name= 408
stuNo= 2012500409 name= 409

 ==>> 结构体:

 ==>> ----------------几种不同的初始化,赋值方式-------------------
s1= { 0 }
字段赋值后:s1= {小脑斧 18 清华大学}
age= 18
==>> 声明时直接给属性赋值:
stu= {脑斧 18 peking}
==>> 使用指针赋值:
指针方式: s= {脑斧 18 }
==>> & 取地址:
s2= {小脑斧 0 清华大学}
==>> & 取地址,并初始化属性:
s3= {脑斧 18 peking}
==.>> 两个结构体之间强制转换:
stu2 = Student(p): stu2= {0}
==>> 起别名:
student= {20}
stuAlias= {20}
StuAlias-> Student: student= {20}

==>> 方法:
==>> -----------------------------------
A.num= 18
==>> 方法值传递测试:
aTest.Num= 18
aTest.Num 更新后,并未改变:aTest= {18}
==>> 方法使用地址传递:
aTest.Num= 18
使用 &aTest调用 aTest.Num 更新后:aTest= {19}
使用默认传地址: aTest.Num 更新后:aTest= {20}

==>> 基础数据类型别名绑定方法:
i=  20
==>> 方法体内修改(i=18)后:
i=  18
i= 18

==>> 结构体实现 String() 方法:
human= {linux 18}
使用 &human 可以调用 String() 方法:
 &human= Name= linux, Age= 18

==>> 跨包创建结构体测试:
modelStu= {脑斧 18}
==>> 跨包创建结构体, 首字母小写,使用方法暴露:
lowCaseModelStu= {小脑斧 19}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值