Go 语言(Golang)基础学习笔记(二)

导读:本篇文章讲解 Go 语言(Golang)基础学习笔记(二),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

教程推荐:

1.Go 语言教程
2.Go语言圣经(中文版)
3.Go语言高级编程
4.Go语言中文网
5.8小时转职Golang工程师(如果你想低成本学习Go语言)

1 、import导包

<1> import导包路径问题与init方法调用流程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
lib1.go:

package lib1

import "fmt"

// Lib1Test 当前lib1包提供的API
func Lib1Test() {
	fmt.Println("lib1Test()...")
}

func init() {
	fmt.Println("lib1. init() ...")
}

lib2.go:

package lib2

import "fmt"

// Lib2Test 当前lib2包提供的API
func Lib2Test() {
	fmt.Println("lib2Test()...")
}

func init() {
	fmt.Println("lib2. init() ...")
}

main.go:

package main

import (
	"5-init/lib1"
	"5-init/lib2"
	"fmt"
)

func main() {
	fmt.Println("main")
	lib1.Lib1Test()
	lib2.Lib2Test()
}

在这里插入图片描述

<2> 函数名首字母大小写问题

函数名首字母大写则可以在外部调用,小写则不可以

//可以在外部调用
func LibTest() {
	fmt.Println("libTest()...")
}
//不可以在外部调用
func libTest()  {
	fmt.Println("libTest()...")
}

<3> import匿名及别名导包方式

正常导包若不使用会报错,若则时想使用包的init方法则可以设置匿名及别名
在这里插入图片描述

【1】设置匿名

在这里插入图片描述

package main

import (
	_ "5-init/lib1"
	"5-init/lib2"
	"fmt"
)

func main() {
	fmt.Println("main")
	//lib1.Lib1Test()
	lib2.Lib2Test()
}

在这里插入图片描述

【2】设置别名

在这里插入图片描述

package main

import (
	mylib "5-init/lib1"
	"5-init/lib2"
	"fmt"
)
//E:/Project/GO/GoLangStudy/5-init/lib1
func main() {
	fmt.Println("main")
	mylib.Lib1Test()
	lib2.Lib2Test()
}

在这里插入图片描述

【3】直接使用.

在这里插入图片描述

package main

import (
	. "5-init/lib1"
	"5-init/lib2"
	"fmt"
)

func main() {
	fmt.Println("main")
	Lib1Test()
	lib2.Lib2Test()
}

2、Golang中的指针速通

<1> &:取地址

package main

import "fmt"

func main() {
	a := 12
	fmt.Println(&a)
}

在这里插入图片描述

<2> *取值所对应的地址的值

package main

import "fmt"

func main() {
	a := 12
	ip := &a
	fmt.Println("a的址址 = &a = ip :",ip)
	fmt.Println("a的值 = a = *ip :",*ip)
}

在这里插入图片描述

<3> 应用

package main

func changValue(p *int)  {
	*p = 99
}

func main() {
	a := 12
	changValue(&a)
	print("a: ",a)
}

在这里插入图片描述

3、 defer关键字

<1> defer定义语句

package main

import "fmt"

func main() {
	//写入defer关键字,在当前函数准备结束前执行
	defer fmt.Println("main end1")
	defer fmt.Println("main end2")


	fmt.Println("main::hello go 1")
	fmt.Println("main::hello go 2")
}

栈式,先defer定义的后执行
在这里插入图片描述

<2> defer定义函数

package main

import "fmt"

func printData()  {
	fmt.Println("printData end")
}

func main() {
	//写入defer关键字,在当前函数准备结束前执行
	defer printData()

	fmt.Println("main::hello go 1")
	fmt.Println("main::hello go 2")
}

在这里插入图片描述

<3> return 先于defer 执行

package main

import "fmt"

func deferPrint() {
	fmt.Println("defet")
}

func deferReturn() int{
	fmt.Println("return")
	return 1
}

func printData() int {
	defer deferPrint()
	return deferReturn()
}

func main() {
	printData()
}

在这里插入图片描述

4、Go 语言的类

Go 语言的类其实是结构体绑定的方式:

<1> 使用结构体

package main

import "fmt"

// Hero 如果类名首字母大写,表示其他包也能够访问
type Hero struct {
	//如果说类的属性首字母大写, 表示该属性是对外能够访问的,否则的话只能够类的内部访问
	Name  string
	Ad    int
	level int
}

func (t Hero) Show() {
    fmt.Println("Name = ", t.Name)
    fmt.Println("Ad = ", t.Ad)
    fmt.Println("Level = ", t.level)
}

func (t Hero) GetName() string {
    return t.Name
}

func (t Hero) SetName(newName string) {
    //t 是调用该方法的对象的一个副本(拷贝)
    t.Name = newName
}

func main() {
	//创建一个对象
	hero := Hero{Name: "zhang3", Ad: 100}

	hero.Show()
	hero.SetName("li4")
	fmt.Println("== SetName 后 ===")
	hero.Show()
}

在这里插入图片描述

但此时内存地址并不一致,所以:

<2> 使用结构体 + 指针

在这里插入图片描述

package main

import "fmt"

// Hero 如果类名首字母大写,表示其他包也能够访问
type Hero struct {
	//如果说类的属性首字母大写, 表示该属性是对外能够访问的,否则的话只能够类的内部访问
	Name  string
	Ad    int
	level int
}

func (t Hero) Show() {
    fmt.Println("Name = ", t.Name)
    fmt.Println("Ad = ", t.Ad)
    fmt.Println("Level = ", t.level)
}

func (t *Hero) GetName() string {
    return t.Name
}

func (t *Hero) SetName(newName string) {
    //t 是调用该方法的对象的一个副本(拷贝)
    t.Name = newName
}

func main() {
	//创建一个对象
	hero := Hero{Name: "zhang3", Ad: 100}

	hero.Show()
	hero.SetName("li4")
	fmt.Println("== SetName 后 ===")
	hero.Show()
}

在这里插入图片描述

5、Go 语言的封装(首字母大小写)

Go 语言 通过首字母是否大写来判别 类(结构体)、方法和变量是否对开放,
首字母大写则外部其他包也可以访问。

6、(类继承)Golang中面向对象继承

package main

import "fmt"

type Human struct {
	name string
	sex  string
}

func (t *Human) Eat() {
	fmt.Println("Human.Eat()...")
}

func (t *Human) Walk() {
	fmt.Println("Human.Walk()...")
}

//=================

type SuperMan struct {
	Human //SuperMan类继承了Human类的方法

	level int  // 新增变量属性
}

// Eat 重定义父类的方法Eat()
func (t *SuperMan) Eat() {
	fmt.Println("SuperMan.Eat()...")
}

// Fly 子类的新方法
func (t *SuperMan) Fly() {
	fmt.Println("SuperMan.Fly()...")
}

func (t *SuperMan) Print() {
	fmt.Println("name = ", t.name)
	fmt.Println("sex = ", t.sex)
	fmt.Println("level = ", t.level)
}

func main() {
	h := Human{"zhang3", "female"}

	h.Eat()
	h.Walk()

	//定义一个子类对象
	//s := SuperMan{Human{"li4", "female"}, 88}
	var s SuperMan
	s.name = "li4"
	s.sex = "male"
	s.level = 88

	s.Walk() //父类的方法
	s.Eat()  //子类的方法
	s.Fly()  //子类的方法

	s.Print()
}

在这里插入图片描述

7、接囗

<1> Golang中面向对象多态的实现与基本要素

package main

import "fmt"

//本质是一个指针
type AnimalIF interface {
	Sleep()
	GetColor() string //获取动物的颜色
	GetType() string  //获取动物的种类
}

// Cat 具体的类
type Cat struct {
	color string //猫的颜色
}

// Sleep Cat 实现接口的方法
func (t *Cat) Sleep() {
	fmt.Println("Cat is Sleep")
}

// GetColor Cat 实现接口的方法
func (t *Cat) GetColor() string {
	return t.color
}

// GetType Cat 实现接口的方法
func (t *Cat) GetType() string {
	return "Cat"
}

// Dog 具体的类
type Dog struct {
	color string
}

// Sleep Dog 实现接口的方法
func (t *Dog) Sleep() {
	fmt.Println("Dog is Sleep")
}

// GetColor Dog 实现接口的方法
func (t *Dog) GetColor() string {
	return t.color
}

// GetType Dog 实现接口的方法
func (t *Dog) GetType() string {
	return "Dog"
}

func showAnimal(animal AnimalIF) {
	animal.Sleep() //多态
	fmt.Println("color = ", animal.GetColor())
	fmt.Println("kind = ", animal.GetType())
}

func main() {

	var animal AnimalIF //接口的数据类型, 父类指针
	animal = &Cat{"Green"}

	animal.Sleep() //调用的就是Cat的Sleep()方法 , 多态的现象

	animal = &Dog{"Yellow"}

	animal.Sleep() // 调用Dog的Sleep方法,多态的现象

	cat := Cat{"Green"}
	dog := Dog{"Yellow"}

	fmt.Println("==== cat: ===")
	showAnimal(&cat)
	fmt.Println("==== dog: ===")
	showAnimal(&dog)
}

在这里插入图片描述

<2> interface空接口万能数据类型与数据类型断言机制

【1】interface空接口万能数据类型

interface空接口万能类型,可以接收任何数据

package main

import "fmt"

//interface{}是万能数据类型
func myFunc(arg interface{}) {
	fmt.Println(arg)
}

type Book struct {
	auth string
}

func main() {
	book := Book{"Golang"}
	myFunc(book)
	
	myFunc(100)
	
	myFunc("abc")
	
	myFunc(3.14)
}

在这里插入图片描述

【2】数据类型断言机制

package main

import "fmt"

//interface{}是万能数据类型
func myFunc(arg interface{}) {
	fmt.Println(arg)

	//interface{} 改如何区分 此时引用的底层数据类型到底是什么?

	//给 interface{} 提供 “类型断言” 的机制
	// arg.(string) : 判断arg是否是string类型
	value, ok := arg.(string)
	if !ok {
		fmt.Printf("arg不是字符串类型\n\n")
	} else {
		fmt.Printf("arg是字符串类型, value = %s\n\n", value)
	}
}

type Book struct {
	auth string
}

func main() {
	book := Book{"Golang"}
	myFunc(book)
	
	myFunc(100)
	
	myFunc("abc")
	
	myFunc(3.14)
}

在这里插入图片描述

8、反射,变量原型

<1> 变量的内置pair结构

package main

import "fmt"

func main() {

	var a string
	//pair<statictype:string, value:"aceld">
	a = "aceld"

	//pair<type:string, value:"aceld">
	var allType interface{}
	allType = a

	str, _ := allType.(string)
	fmt.Println(str)
}

在这里插入图片描述

<2> reflect 反射包

package main

import (
	"fmt"
	"reflect"
)

func reflectNum(arg interface{}) {
	fmt.Println("type : ", reflect.TypeOf(arg))
	fmt.Println("value : ", reflect.ValueOf(arg))
}

func main() {
	var num float64 = 1.2345

	reflectNum(num)
}

在这里插入图片描述

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id   int
	Name string
	Age  int
}

func (t User) Call() {
	fmt.Println("user is called ..")
	fmt.Printf("%v\n", t)
}

func main() {
	user := User{1, "Aceld", 18}

	DoFiledAndMethod(user)
}

func DoFiledAndMethod(input interface{}) {
	//获取input的type
	inputType := reflect.TypeOf(input)
	fmt.Println("inputType is :", inputType.Name())

	//获取input的value
	inputValue := reflect.ValueOf(input)
	fmt.Println("inputValue is:", inputValue)

	//通过type 获取里面的字段
	//1. 获取interface的reflect.Type,通过Type得到NumField ,进行遍历
	//2. 得到每个field,数据类型
	//3. 通过filed有一个Interface()方法等到 对应的value
	for i := 0; i < inputType.NumField(); i++ {
		field := inputType.Field(i)
		value := inputValue.Field(i).Interface()

		fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
	}

	//通过type 获取里面的方法,调用
	for i := 0; i < inputType.NumMethod(); i++ {
		m := inputType.Method(i)
		fmt.Printf("%s: %v\n", m.Name, m.Type)
	}

}

在这里插入图片描述

8、结构体标签

<1> 使用结构体标签Tag

在这里插入图片描述

type resume struct {
	Name string `info:"name" doc:"我的名字"`
	Sex  string `info:"sex"`
}

<2> golang反射解析结构体标签Tag

package main

import (
	"fmt"
	"reflect"
)

type resume struct {
	Name string `info:"name" doc:"我的名字"`
	Sex  string `info:"sex"`
}

func findTag(str interface{}) {
	t := reflect.TypeOf(str).Elem()

	for i := 0; i < t.NumField(); i++ {
		taginfo := t.Field(i).Tag.Get("info")
		tagdoc := t.Field(i).Tag.Get("doc")
		fmt.Println("info: ", taginfo, " doc: ", tagdoc)
	}
}

func main() {
	var re resume

	findTag(&re)

}

在这里插入图片描述

<2> 使用结构体标签让结构体与json数据相互转互

【1】结构体转为json数据:

package main

import (
	"encoding/json"
	"fmt"
)

type Movie struct {
	Title  string   `json:"title"`
	Year   int      `json:"year"`
	Price  int      `json:"rmb"`
	Actors []string `json:"actors"`
}

func main() {
	movie := Movie{"喜剧之王", 2000, 10, []string{"xingye", "zhangbozhi"}}

	//结构体转为json数据
	jsonStr, err := json.Marshal(movie)
	// 判断
	if err != nil {
		fmt.Println("json marshal error", err)
		return
	}

	fmt.Printf(string(jsonStr))
}

在这里插入图片描述

【2】json数据 转为结构体:

package main

import (
	"encoding/json"
	"fmt"
)

type Movie struct {
	Title  string   `json:"title"`
	Year   int      `json:"year"`
	Price  int      `json:"rmb"`
	Actors []string `json:"actors"`
}

func main() {
	movie := Movie{"喜剧之王", 2000, 10, []string{"xingye", "zhangbozhi"}}

	//结构体转为json数据
	jsonStr, err := json.Marshal(movie)
	// 判断
	if err != nil {
		fmt.Println("json marshal error", err)
		return
	}

	//json数据转为结构体 
	//jsonStr = {"title":"喜剧之王","year":2000,"rmb":10,"actors":["xingye","zhangbozhi"]}
	myMovie := Movie{}
	err = json.Unmarshal(jsonStr, &myMovie)
	if err != nil {
		fmt.Println("json unmarshal error ", err)
		return
	}

	fmt.Printf("%v\n", myMovie)
}

在这里插入图片描述

9、(goroutine)并发 基本模型和调度设计策略

<1> 图示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

<2> 匿名函数

定义匿名函数并调用:

func() {
	fmt.Println("Hello World")
}()

有参:

func(a int) {
	fmt.Println(a)
}(10)

赋值:

myfun := func(a int) {
	fmt.Println(a)
}
myfun(10)

10、通道(channel):进程间通信

channel:是一种数据类型

<1>定义通道

定义一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:

ch := make(chan int)

// 带缓冲
ch := make(chan int, 3)

<2> 简单使用

在这里插入图片描述

package main

import "fmt"

func main() {
	//定义一个channel
	channel := make(chan int)

	go func() {
		channel <- 666 //将666 发送给chan
	}()

	num := <-channel//从chan中接受数据,并赋值给num
	fmt.Println("num = ", num)
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

<3> channel有缓冲与无缓冲同步问题

无缓冲channel:
无缓冲channel
有缓冲channel:
在这里插入图片描述

package main

import (
	"fmt"
	"time"
)

func main() {
	channel := make(chan int, 3) //带有缓冲的channel

	fmt.Println("len(channel) = ", len(channel), ", cap(channel) = ", cap(channel))

	go func() {
		defer fmt.Println("子go程结束")

		for i := 0; i < 4; i++ {
			channel <- i
			fmt.Println("子go程正在运行, 发送的元素=", i, " len(channel)=", len(channel), ", cap(channel)=", cap(channel))
		}
	}()

	time.Sleep(2 * time.Second)

	for i := 0; i < 4; i++ {
		num := <-channel //从c中接收数据,并赋值给num
		fmt.Println("num = ", num)
	}

	fmt.Println("main 结束")
}

在这里插入图片描述

<4> channel的关闭特点

【1】channel关闭

package main

import "fmt"

func main() {
	c := make(chan int)

	go func() {
		for i := 0; i < 5; i++ {
			c <- i
		}

		//close可以关闭一个channel
		close(c)
	}()
	
	for {
		//ok如果为true表示channel没有关闭,如果为false表示channel已经关闭
		if data, ok := <-c; ok {
			fmt.Println(data)
		} else {
			break
		}
	}

	fmt.Println("Main Finished..")
}
  • channel不像⽂件⼀样需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的,才去关闭channel;
  • 关闭channel后,⽆法向channel 再发送数据(引发 panic 错误后导致接收⽴即返回零值);
  • 关闭channel后,可以继续从channel接收数据;
  • 对于nil channel,⽆论收发都会被阻塞。

【2】channel与range

可以使用range来迭代不断操作channel

package main

import "fmt"

func main() {
	c := make(chan int)

	go func() {
		for i := 0; i < 5; i++ {
			c <- i
		}

		//close可以关闭一个channel
		close(c)
	}()

	//可以使用range来迭代不断操作channel
	for data := range c {
		fmt.Println(data)
	}

	fmt.Println("Main Finished..")
}

在这里插入图片描述

【3】channel与select

package main

import "fmt"

func fibonacii(c, quit chan int) {
	x, y := 1, 1

	for {
		select {
		case c <- x:
			//如果c可写,则该case就会进来
			x = y
			y = x + y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	//sub go
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}

		quit <- 0
	}()

	//main go
	fibonacii(c, quit)
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92675.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!