go语言入门

切片类型

数组是值传递类型,切片(slice)是对数组的一个连续“片段”的引用,所以切片是一个引用类型。

数组声明:var arr [index]int
切片:arr:=make([ ]int,10)

map类型

  1. map定义

    Go语言中的一种特殊类型,一种“元素对”的无序集合元素对包含一个key(索引)和一个value(值),也称为“关联数组”。这是一种能够快速寻找值的理想结构:给定一个key就可以迅速找到对应的value。
    map是一种引用类型,声明方式:

var name map[key_type]value_type

例:

var literalMap map[string]string
	var assignedMap map[string]string

	literalMap = map[string]string{"first": "go", "second": "web"}
	createMap := make(map[string]float32)
	assignedMap = literalMap
	createMap["k1"] = 99
	createMap["k2"] = 108
	assignedMap["second"] = "program"

	fmt.Println(literalMap["first"])
	fmt.Println(assignedMap["second"])
	fmt.Println(createMap["k1"])
	fmt.Println(literalMap["third"])
	
运行结果:
go
program
99

assignedMap是literalMap 的引用,对assignedMap的修改也会影响literalMap 的值。
可以用make()函数构造map,但不能使用new()函数来构造。

	//new()函数构造
	crete2Map := new(map[string]float32)
	crete2Map["k1"] = 10086
	
# main/pritice/map
.\main.go:14:11: invalid operation: cannot index crete2Map (variable of type *map[string]float32)
.\main.go:20:23: invalid operation: cannot index crete2Map (variable of type *map[string]float32)
  1. map容量
    和数组不同,map可以根据新增的元素对来动态地伸缩,因此它不存在固定长度或最大限制。但也可以选择标明map的容量capacity,格式如下:

make(map[key_type]value_type,cap)

例如:

map:=make(map[string]string,10)

当map增长到容量上限后,如果在增加新的元素对,则map的大小会自动加1
例:

literalMap = map[string]string{
		"first": "go", "second": "web",
		"third":"haha","woo":"fire",
		}
  1. 用切片作为map的值
    既然一个key对应一个value,而value又是一个原始类型,那么一个key要对应多个值怎么办?
    通过将value定义为[]int类型或者其他类型的切片,就可以优雅的解决这个问题了,如下:
map1:=make(map[int] []int)
map2:=make(map[int] *[]int)

匿名函数

匿名函数也称为“闭包”,是指一类无需定义标识符(函数名)的函数或子程序,匿名函数往往以变量方式被传递。

  1. 匿名函数的定义
    匿名函数可以理解为没有函数名的普通函数,定义如下:

func (参数列表) (返回值列表) { //函数体 }

匿名函数是一个“内联”语句表达式。匿名函数的优越性在于:可以直接使用函数内的变量,不必声明。
实例:

func main() {
	x, y := 10, 20
	// 匿名函数
	defer func(a int) {
		fmt.Println("defer x,y=", a, y)
	}(x)
	x += 10
	y += 100
	fmt.Println(x, y)
}
运行结果:
PS E:\Go_work\src\main\pritice\func> .\func.exe
20 120
defer x,y= 10 120
  1. 匿名函数的调用
    (1) 在定义时调用匿名函数
    匿名函数可以在声明后调用或者声明时直接调用,例:
//	定义匿名函数并赋值给f变量
f := func(data int) {
	fmt.Println("hi this is closure", data)
}
f(6)
//	直接声明并调用
func(data int) {
	fmt.Println("hi this is closure,directly", data)
}(8)

运行结果:
PS E:\Go_work\src\main\pritice\func> .\func.exe
hi this is closure 6
hi this is closure,directly 8

匿名函数的用途非常广泛。匿名函数本身是一种值,可以方便地保存在各种容器中实现回调函数和操作封装。
(2)用匿名函数作为回调函数
回调函数简称“回调”,是指通过函数参数传递到其他代码的某一块可执行代码的引用。
匿名函数作为回调函数来使用,在go语言的系统包中是很常见的,在string包中就有这种实现:

func TrimFunc(s string,f func(rune) bool) string {
	return TrimRightFunc(TrimLeftFunc(s,f),f)
}

可以使用匿名函数作为参数,来实现对切片中的元素的遍历操作,例:

func visitPrint(list []int, f func(int)) {
	for _, value := range list {
		f(value)
	}
}
func main() {
	sli := []int{1, 6, 8}
	//仔细观察函数结构,琢磨匿名函数回调的过程
	visitPrint(sli, func(value int) {
		fmt.Println(value)
	})
}

运行结果:
PS E:\Go_work\src\main\pritice\func> .\func.exe
1
6
8

defer 延迟语句

  1. 什么是defer延迟语句
    在函数中,经常需要创建资源(比如数据库连接,文件句柄,锁等)。为了在函数执行完毕后及时地释放资源,Go的设计者提供defer延迟语句。
    defer语句主要用在函数中,用在函数结束(return 或 panic 异常导致结束) 之前执行某个动作,是一个函数结束前最后执行的动作。
    在Go语言一个函数中,defer 语句的执行逻辑如下。
    (1)当程序执行到一个defer时,不会立即执行defer 后的语句,而是将defer后的语句压入一个专门储存defer语句的栈中,然后继续执行函数的下一个语句。
    (2)当函数执行完毕后,再从defer栈中依次从栈顶取出语句执行(注:先进去的最后执行,最后进去的最先执行,栈的特点,先进后出)。
    (3)在defer将语句放入栈时,也会将相关的值复制进入栈中。
    例:
func main() {
	deferCall()
}
func deferCall() {
	defer func1()
	defer func2()
	defer func3()
}
func func1() {
	fmt.Println("A")
}
func func2() {
	fmt.Println("B")
}
func func3() {
	fmt.Println("C")
}
运行结果:
PS E:\Go_work\src\main\pritice\defer> .\defer.exe    
C
B
A
  1. defer与return的执行顺序
  • 先为返回值赋值,即将返回值放到一个临时变量中,然后执行defer,然后return到函数被调用处。
  • 如果所在函数为有名返回值函数,return第一步先把返回值放到有名返回值变量中,如果恰好defer函数中修改了该返回值,那么最终返回值是更新后的。但是如果所在函数为无名返回值函数,那么return第一步先把返回值放到一个临时变量中,defer函数无法获取到这个临时变量地址,所以无论defer函数做任何操作,都不会对最终返回值造成任何变动。

例1:无名返回值(即函数返回值为没有命名的返回值)
(1)

var name string = "go"

func myfunc() string {
	defer func() {
		name = "python"
	}()
	fmt.Println("myfunc()函数里的name: ", name)
	return name
}
func main() {
	myname := myfunc()
	fmt.Println("main()函数例的name:  ", name)
	fmt.Println("main()函数里的mynane:   ", myname)
}
运行结果:
PS E:\Go_work\src\main\pritice\defer> .\defer.exe
myfunc()函数里的name:  go
main()函数例的name:   python
main()函数里的mynane:    go

(2)

func reint() int {
	var x int
	defer func() {
		x++
		fmt.Println("defer1=", x)
	}()
	defer func() {
		x++
		fmt.Println("defer2=", x)
	}()
	return x
}
func main() {
	fmt.Println("return= ", reint())
}
运行结果:
PS E:\Go_work\src\main\pritice\defer> .\defer.exe
defer2= 1
defer1= 2
return=  0

例2:有名返回值(函数返回值为已经命名的返回值)

func reint() (x int) {
	defer func() {
		x++
		fmt.Println("defer1=", x)
	}()
	defer func() {
		x++
		fmt.Println("defer2=", x)
	}()
	return x
}

func main() {
	fmt.Println("return= ", reint())
}
运行结果:
PS E:\Go_work\src\main\pritice\defer> .\defer.exe
defer2= 1
defer1= 2
return=  2
  • defer常用应用场景
    (1)关闭资源
    (2)与recover()函数一起使用
    当程序出现宕机或者遇到panic错误时,recover()函数可以恢复执行,而且不会报宕机错误。之前说过,defer不但可以在return返回前调用,也可以在程序宕机显示panic错误时,在程序出现宕机之前被执行,依次来恢复程序。

Go面向对象编程

 面向对象只是一种编程思想。面向对象有三大基本特征。
  • 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
  • 继承:使得子类具有父类的属性和方法或者重新定义,追加属性和方法等。
  • 多态:不同对象中同种行为的不同实现方式。

封装

1.属性
Go语言使用结构体对属性进行封装。结构体就像是类的一种简化形式。例如,我们要定义一个三角形,每个三角形都有底和高。可以这样进行封装:

	type Triangle struct{
		Bottom float32
		Height float32
	}

2.方法
既然有了“类”,那么“类”的方法在哪里呢?Go语言中也有方法(Methods)。方法是作用在接受者(receiver)上的一个函数,接受者是某种类型的变量。因此,方法是一种特殊类型的函数。

package main

import "fmt"

type Triangle struct {
	Bottom float32
	Height float32
}

// 定义一个 Area 对三角形面积进行计算
func (t *Triangle) Area() float32 {
	return (t.Height * t.Bottom) / 2
}
func main() {
	//声明一个 Triangle 类型变量
	r := &Triangle{6, 8}
	//调用 Area 方法计算面基
	fmt.Println(r.Area())
}
运行结果:
24

3.访问权限
Go语言通过字母大小写来控制可见性的

继承

Go语言中没有extends关键字,而是使用在结构体中内嵌匿名类型的方法来实现继承。例如,定义一个Engine接口类型和一个Bus结构体,让Bus结构体包含一个Engine接口的匿名字段:

type Engine interface {
	Run()
	Stop()
}
type Bus struct {
	Engine  //包含Engine类型的匿名字段
}
//此时,Engine里面的方法“晋升”为外层Bus里面的方法
func (b *Bus) Working() {
	b.Run()
	b.Stop()
}

多态

在面向对象中,多态的特征是不同对象中同种行为的不同实现方式。在Go语言中可以使用接口实现这个特征。

//多态

// Square 正方形结构体
type Square struct {
   sideLen float32
}

// Triangle 三角形结构体
type Triangle struct {
   Bottom float32
   Height float32
}

// Shape 接口
type Shape interface {
   Area() float32
}

// Area 计算三角形的面积
func (t *Triangle) Area() float32 {
   return t.Bottom * t.Height / 2
}

// 计算正方形的面积
func (s *Square) Area() float32 {
   return s.sideLen * s.sideLen
}
func main() {
   t := &Triangle{6, 8}
   s := &Square{8}
   shapes := []Shape{t, s}
   for n, _ := range shapes {
   	fmt.Println("图形数据是:", shapes[n])
   	fmt.Println("面积是:", shapes[n].Area())
   }
}
运行结果:
图形数据是: &{6 8}
面积是: 24
图形数据是: &{8}
面积是: 64

接口

接口(interface)类型是对其他类型行为的概括与抽象。接口类型定义一组方法,但是不包含这些方法的具体实现。
接口本质是一种类型,(指针类型),接口可以实现多态功能。

type dog struct{}

func (d *dog) say() {
   fmt.Println("汪汪汪~")
}

type cat struct{}

func (c *cat) say() {
   fmt.Println("喵喵喵~")
}

type sayer interface {
   say()
}

func da(arg sayer) {
   arg.say()
}
func main() {
   d := dog{}
   da(&d)
   c := cat{}
   da(&c)
}
空接口

如果接口没有任何方法声明,则为空接口(interface{})。它的用途类似面向对象里的根类型,可以被赋值为任何类型的对象。
将空接口作为函数参数,代表该函数可以接收任意参数。map,silce 也可以用接口实现。

断言

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值