本文共 5866 字,大约阅读时间需要 19 分钟。
任何程序数据载入内存后,在内存都有他们的地址,这就是指针。而为了保存一个数据在内存中的地址,我们就需要指针变量。
地址:就是内存地址(用字节来描述的内存地址)指针:指针是带类型的。
&和*
&:表示取地址*:根据地址取值
定义一个变量:
var a int
取变量a的内存地址:
b := &a
取地址对应的值:
fmt.Println(*b)
定义一个修改数组第一个元素为100的函数:
func modifyArray(a1 [3]int) { a1[0] = 100 //只是修改的内部的a1这个数组}
定义一个修改数组第一个元素为100的函数,接收的参数是一个数组的指针
func modifyArray2(a1 *[3]int) { // (*a1)[0] = 100 //只是修改的内部的a1这个数组 //语法糖:因为Go语言中指针不支持修改 a1[0] = 100 //只是修改的内部的a1这个数组}
二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);
而new用于类型的内存分配,并且内存置为零。所以在我们编写程序的时候,就可以根据自己的需要很好的选择了。
make返回的还是这三个引用类型本身;而new返回的是指向类型的指针。
new()
该方法的参数要求传入一个类型,而不是一个值,它会申请一个该类型大小的内存空间,并会初始化为对应的零值,返回指向该内存空间的一个指针。如下:
func new(Type) *Type
make()
make也是用于内存分配,但是和new不同,它只用于slice、map和channel的内存创建,它返回的类型就是类型本身,而不是它们的指针类型。
func make(t Type, size ...IntegerType) Type
案例:
package mainimport "fmt"func main() { // 以下是错误的写法 // var a *int //a是一个int类型的指针 // var b *string // var c *[3]int // 以上是错误的写法 var a = new(int) //得到一个int类型的指针 fmt.Println(a) *a = 10 fmt.Println(a) fmt.Println(*a) var c = new([3]int) fmt.Println(c) c[0] = 1 fmt.Println(*c)}
其实,Go语言是不支持 try…catch…finally 这种异常处理的,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。
在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,才使用Go中引入的Exception处理:defer, panic, recover。
panic:运行时异常
panic用法挺简单的, 其实就是throw exception。
panic是golang的内建函数,panic会中断函数F的正常执行流程, 从F函数中跳出来, 跳回到F函数的调用者. 对于调用者来说, F看起来就是一个panic, 所以调用者会继续向上跳出, 直到当前goroutine返回. 在跳出的过程中, 进程会保持这个函数栈. 当goroutine退出时, 程序会crash。
要注意的是, F函数中的defered函数会正常执行, 按照上面defer的规则。
同时引起panic除了我们主动调用panic之外, 其他的任何运行时错误, 例如数组越界都会造成panic
panic用法:
package mainimport ( "fmt")func main() { test()}func test() { defer func() { fmt.Println("打印前") }() defer func() { fmt.Println("打印中") }() defer func() { fmt.Println("打印后") }() panic("触发异常") fmt.Println("test")}-------output-------打印后 打印中 打印前 panic: 触发异常 goroutine 1 [running]: main.test() D:/Go_Path/go/src/logDemo/main.go:15 +0x98 main.main() D:/Go_Path/go/src/logDemo/main.go:8 +0x27 exit status 2```**recover:用来将函数在panic时恢复回来,用于做一些资源回收的操作**recover也是golang的一个内建函数, 其实就是try catch。不过需要注意的是: 1. recover如果想起作用的话, 必须在defered函数中使用。 2. 在正常函数执行过程中,调用recover没有任何作用, 他会返回nil。如这样:fmt.Println(recover()) 。 3. 如果当前的goroutine panic了,那么recover将会捕获这个panic的值,并且让程序正常执行下去。不会让程序crash。**recover 用法:**```gofunc main() { fmt.Println("c") defer func() { // 必须要先声明defer,否则不能捕获到panic异常 fmt.Println("d") if err := recover(); err != nil { fmt.Println(err) // 这里的err其实就是panic传入的内容 } fmt.Println("e") }() f() //开始调用f fmt.Println("f") //这里开始下面代码不会再执行}func f() { fmt.Println("a") panic("异常信息") fmt.Println("b") //这里开始下面代码不会再执行}-------output-------cad异常信息e
type关键字用来在Go语言中定义新的类型。
创造一个新类型
type NewInt int
类型别名(软链)
var MyInt = int
byte: uint8 和 rune:int32是Go语言内置的别名。
类型别名只在代码编写过程中生效,编译完不存在。
//结构体 // 创在新的类型要使用type关键字 type student struct { name string age int gender string hobby []string } func main() { var haojie = student{ name: "豪杰", age: 19, gender: "男", hobby: []string{ "篮球", "足球", "双色球"}, } //结构体支持.访问属性 fmt.Println(haojie) fmt.Println(haojie.name) fmt.Println(haojie.age) fmt.Println(haojie.gender) fmt.Println(haojie.hobby) }
var haojie = student{ name: "豪杰", age: 19, gender: "男", hobby: []string{ "篮球", "足球", "双色球"}, }
结构体支持.访问属性
fmt.Println(haojie) fmt.Println(haojie.name) fmt.Println(haojie.age) fmt.Println(haojie.gender) fmt.Println(haojie.hobby)
实例化方法1
// struct是值类型的 // 如果初始化时没有给属性(字段)设置对应的初始值,那么对应属性就是其类型的默认值 var wangzhan = student{ } fmt.Println(wangzhan.name) fmt.Println(wangzhan.age) fmt.Println(wangzhan.gender) fmt.Println(wangzhan.hobby)
实例化方法2 new(T) T:表示类型或结构体
var yawei = new(student) fmt.Println(yawei) // (*yawei).name yawei.name = "亚伟" yawei.age = 18 fmt.Println(yawei.name, yawei.age) // 实例化方法3 var nazha = &student{ } fmt.Println(nazha) nazha.name = "沙河娜扎" fmt.Println(nazha.name)
var stu1 = student{ "豪杰", 18, "男", []string{ "男人", "女人"}, } fmt.Println(stu1.name, stu1.age) //键值对初始化 var stu2 = &student{ name: "豪杰", gender: "男", } fmt.Println(stu2.name, stu2.age, stu2.gender)}
// 内存是以字节为单位的十六进制数// 1字节 = 8位 = 8bitfunc main() { type test struct { a int16 b int16 c int16 } var t = test{ a: 1, b: 2, c: 3, } fmt.Println(&(t.a)) fmt.Println(&(t.b)) fmt.Println(&(t.c))}
方法就是某个具体的类型才能调用的函数,Go的方法是在函数前面加上一个接收者。
type people struct { name string gender string}//函数指定接受者之后就是方法// 在go语言中约定成俗不用this也不用self,而是使用后面类型的首字母的小写func (p *people) dream() { p.gender = "男" fmt.Printf("%s的梦想是不用上班也有钱拿!\n", p.name)}func main() { var haojie = &people{ name: "豪杰", gender: "爷们", } // (&haojie).dream() haojie.dream() fmt.Println(haojie.gender)}
package mainimport "fmt"// 可以给任意类型追加方法// 不能给别的包定义的类型添加方法type MyInt intfunc (m *MyInt) sayHi() { fmt.Println("Hello MyInt~")}func main() { var a MyInt fmt.Println(a) a.sayHi()}
func newStudent(n string, age int, g string, h []string) *student { return &student{ name: n, age: age, gender: g, hobby: h, }
package mainimport "fmt"// 结构体内嵌模拟“继承”type animal struct { name string}//定义一个动物会动的方法func (a *animal) move() { fmt.Printf("%s会动~\n", a.name)}//定义一个狗的结构体type dog struct { feet int animal}//定义了一个狗的方法 wangwangfunc (d *dog) wangwang() { fmt.Printf("%s 在叫:汪汪汪~\n", d.name)}func main() { var a = dog{ feet: 4, animal: animal{ name: "旺财", }, } a.wangwang() //调用狗的方法 a.move() //调用动物的方法}
package mainimport "fmt"// 匿名字段type student struct { name string string int}func main() { var stu1 = student{ name: "豪杰", } fmt.Println(stu1.name) fmt.Println(stu1.string) fmt.Println(stu1.int)}
转载地址:http://dzhzi.baihongyu.com/