教程推荐:
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:
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