当前位置: 首页 > news >正文

go进阶学习

go语言进阶学习

值拷贝和地址拷贝分析:

🔒 不会影响源数据(拷贝副本):

  • 基本类型:int, float64, string, bool, rune
  • 数组:[n]int, [3]string
  • 结构体(仅包含上述值类型字段时)

✅ 赋值或传参时,会拷贝完整的数据,修改副本不会影响原数据。


🔄 会影响源数据(共享底层数据 / 传递引用):

  • 指针:*int, *struct
  • 切片:[]int, []string
  • 映射:map[string]int
  • 通道:chan int

结构体struct注意事项:

1,结构体实例给实例赋值,是值传递

2,结构体序列化为json格式

//每个结构体的sturct属性都能定义一个tag标签
type Student struct {Name  string `json:"name"`Age   int    `json:"age"`Score int    `json:"score"`
}func main() {var student object.Student = object.Student{"魏正想", 18, 99}marshal, err := json.Marshal(student)if err != nil {fmt.Println("用户错误")}//将字符数切片转为string类型fmt.Println(string(marshal))
}

方法使用调用String()方法:

*Student类型实现了String方法,输出时输出该方法中的输出格式

type Student struct {Name  string `json:"name"`Age   int    `json:"age"`Score int    `json:"score"`
}func (student *Student) String() string {n := fmt.Sprintf("%v,%v,%v", student.Name, student.Age, student.Score)return n}func main() {var student Student = Student{"www", 19, 56}result := student.String()fmt.Println(result)fmt.Println(&student)
}
//输出格式!!!!!!
//www,19,56

方法与函数的区别:

1,调用方式不一样

函数调用: 函数名加实参列表

方法调用: 变量加方法名加实参列表

2,对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,防止亦然

3,对于方法比如结构体的方法,接收者为值类型时,可以直接用指针类型的变量调用方法,放过来同样也可以

工厂模式(相当于Java的构造函数):

省略哈哈哈哈哈!

go继承:

优势:

1,提高代码的复用性

2,代码的扩展性和维护性提高了

package mainimport "fmt"type student struct {name  stringage   intscore int
}func (stu *student) GetName() string {return stu.name
}type min struct {student
}
type max struct {student
}func main() {//继承练习//记得加= &min{},不然只是定义了类型,未分配内存var aaa *min = &min{}aaa.student.name = "魏正想"aaa.student.age = 20aaa.student.score = 99name := aaa.student.GetName()fmt.Println(name)//可以直接通过aaa这只name名字aaa.name = "lulu"getName := aaa.GetName()fmt.Println(getName)
}

注意点:

1,结构体可以使用嵌套结构体所有字段和方法,即首字母大写或者小写的字段,方法都可以使用

2,如果b继承a,访问name字段时,先看b中有没有name再看a中又没有name字段,如果都找不到就报错

3,当结构体有匿名结构体(继承的结构体)有相同的字段或者方法时,编译器采用就近访问原则访问。

4,如果一个结构体嵌套了一个有名的结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,必须带上结构体的名字。

type student struct {name  stringage   int//如果一个结构体有int类型的匿名字段,就不能有第二个//如果需要多个int字段,则必须给int字段指定名字intscore int
}

go可以嵌入多个类型实现类似多继承的代码复用,本质是组合。

Java中有限制,只能实现单一继承。

go中为了代码的简洁性,尽量避免使用多重继承

go接口:

package mainimport "fmt"type animal interface {eat()sleep()
}type cat struct {
}func (ccc cat) eat() {fmt.Println("cat开始进食")
}
func (ccc cat) sleep() {}type dog struct {
}func (ddd dog) eat() {}func (ddd dog) sleep() {fmt.Println("dog开始睡觉")
}func having(animal2 animal) {animal2.eat()animal2.sleep()
}
func main() {var ccc catvar ddd doghaving(ccc)having(ddd)
}

注意:接口里的所有方法都没有方法体,也不能定义变量(Java中可以)

go接口中不需要显式的实现,只要一个变量,含有接口中的所有方法,变量就实现了这个接口

Java中需要显式实现,需要implement关键字来进行显示实现

go中接口默认是一个指针(引用类型),如果没有对interface初始化就使用,那么会输出nil

空接口interface{}没有任何方法,所以所有类型都实现空接口,即我们可以把任何一个变量赋给空接口

go多态:

文件操作:

读取文件

package mainimport ("bufio""fmt""io""os"
)func main() {file, err := os.Open("1goAdvanced/file/fileReader/aaa.txt")if err != nil {fmt.Println("文件读取异常")}//每次读完要关闭文件,否则会导致内存泄漏defer file.Close()reader := bufio.NewReader(file)for {readString, err := reader.ReadString('\n')if err == io.EOF {break}fmt.Println(readString)}fmt.Println("文件读取结束")
}

go一次性读取文件:

只适合文件比较小的读取,文件太大性能会非常差

ioutil.ReadFile(“文件路径”)

创建文件并写入内容:

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
//创建文件并写入内容
filePath := "d:/abc.txt"
file1, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {fmt.Println("%v", err)
}
defer file1.Close()
str := "helloWorld\n"
writer := bufio.NewWriter(file1)
for i := 0; i < 5; i++ {writer.WriteString(str)
}
//将缓存写入文件中
writer.Flush()

copy(目标文件,源文件)拷贝文件

解析命令行参数

os.Args

flag包

//命令行  test.exe -u root -pwd 1234 -port localhost
var port int
var pwd string
//得到port后面的值,如果没有默认是3306
flag.IntVar(&port, "port", 3306, "端口默认值是3306")
flag.StringVar(&pwd, "pwd", "", "端口")

json概述:

JSON是一种轻量级数据交换格式,特别有利于网络传输

任何数据类型都可以用json来表示

interface{}代表任意类型

序列化Marshal:

json.Marshal( args interface{})

//注意事项:

结构体序列化时,要保证内部属性都是大写字母开头,因为json包跨包序列化,需要结构体内部属性都是可以外部访问的,并且传指针更轻量化一些

type teacher struct {Name stringAge  intJob  string
}func main() {var tea teacher = teacher{Name: "mmm",Age:  11,Job:  "ninin",}marshal, _ := json.Marshal(tea)fmt.Println(string(marshal))}

反序列化Unmarshal:

func Unmarshal(data []byte, v interface{}) error

注意:对于map这种反序列化的结果赋值给一个map实例时,这个map实例不用事先make,因为Unmarshal底层会进行make操作

goroutine(协程):

查看系统cpu(NumCPU):

func main() {cpu := runtime.NumCPU()fmt.Println(cpu)
}

进程和线程的说明:

1,进程是程序在操作系统中一次执行过程,是系统进行资源分配和调度的基本单位

2,线程是进程的一个执行实例,是程序执行的最小单元,是比进程更小的能独立运行的基本单位

3,一个进程可以创建和销毁多个线程,同时一个进程中多个线程可以并发执行

4,一个程序至少有一个进程,一个进程中至少有一个线程

并发和并行:

并发:多任务在一个cpu上运行

并行:多任务在多个cpu上运行

协程基本概念:

1,主线程是一个物理线程,直接作用在cpu上的,是重量级的,非常消耗cpu资源。

2,协程从主线程开启的,是轻量级的线程,是逻辑态,对资源消耗相对较小

3,golang的协程机制是重要的特点,可以轻松的开启上万个协程。其他编程语言的开发机制是一般基于线程的,开启过多的线程,资源消耗大,这里就突显golang在并发上的优势了。

了解go中MPG模式基本介绍。

简介:原来M0主线程正在执行g0协程,另外三个协程在队列等待

如果g0协程阻塞,比如说io操作,这是会创建M1主线程也可能从已有的线程池中取出M1,并将等待的3个协程挂到M1下开始执行,M0主线程仍然执行io操作,不会让队列阻塞。

go协程案例:

// 计算1到20的每个数的阶乘的和
// 定义全局变量
var (nums map[int]int = make(map[int]int, 10)lock             = sync.Mutex{}
)func test(num int) {var temp int = 1for i := 1; i <= num; i++ {temp *= i}lock.Lock()nums[num] = templock.Unlock()
}func main() {//fmt.Println()for i := 1; i <= 20; i++ {//定义协程go test(i)}time.Sleep(time.Second * 5)lock.Lock()for _, num := range nums {fmt.Println(num)}lock.Unlock()
}

channel基本介绍:

特点:

channel本质就是一个数据结构队列

数据是先进先出

channel是线程安全的,多个协程访问时,不用加锁

channel有类型的,一个string的channel只能存放string类型数据

依次取除channel中的数据:

channel两种读取错误分析:

注意:在遍历是len(cha)是动态变化的,每取出一次,channel的长度就会缩短,不能用channel作为限制条件

方式一:❌

var cha chan int// channel初步练习
func main() {//查看运行系统中有几核cpucpu := runtime.NumCPU()fmt.Println(cpu)cha = make(chan int, 3)cha <- 22cha <- 99cha <- 66var temp intfor i := 0; i < len(cha); i++ {temp = <-chafmt.Printf("从管道中提取出数据%v", temp)fmt.Println()}
}

方式二:✔

var cha chan int// channel初步练习
func main() {//查看运行系统中有几核cpucpu := runtime.NumCPU()fmt.Println(cpu)//cha = make(chan int, 3)cha <- 22cha <- 99cha <- 66var length int = len(cha)var temp intfor i := 0; i < length; i++ {temp = <-chafmt.Printf("从管道中提取出数据%v", temp)fmt.Println()}
}

管道使用注意事项:

channel中只能存放指定数据类型

数据放满后就不能在存放,如果取出数据,可以继续放入

在没有使用协程的情况下,如果管道数据取完了, 再取,会报dead lock

对于结构体,在编译时默认是interface

所以需要进行类型断言

类型断言与强制类型转换:

注意:类型转换是“换汤不换药”,给数据换个类型外衣;类型断言是“打开盲盒”,看看接口里到底装了啥。

  • 当你有一个 接口类型的变量,但你想知道它具体是什么类型,并取出该实际值
  • 常用于处理 多种可能的类型,比如空接口 interface{} 包含不同类型数据时

类型断言:

类型断言 是用于 接口类型(interface) 的操作,目的是 从接口变量中提取出它实际存储的具体类型值,或者判断该接口是否实现了某个具体类型或接口。

换句话说:类型断言让你可以检查接口值背后到底是什么具体类型,并获取该值。

//可以接收任何的数据类型
var inter chan interface{} = make(chan interface{}, 3)
inter <- 23.57
inter <- 2222222222222222
type dog struct {name string
}
var doo = dog{name: "mmmmmmmm",
}
inter <- doo
//取出数据
//前一个丢弃
<-inter
bbb := <-inter
fmt.Println(bbb)
sss := <-inter
fmt.Println(sss)
//详细获取到name需要进行类型断言
result := sss.(dog)
fmt.Println(result.name)

管道关闭+channel遍历:

管道遍历,前一定要关闭管道!!!!

var inter chan interface{} = make(chan interface{}, 3)
inter <- 23.57
inter <- 222222
type dog struct {name string
}
var doo = dog{name: "mmmmmmmm",
}
inter <- doo
//管道遍历,前一定要关闭管道
close(inter)
for v := range inter {fmt.Println(v)
}
http://www.dtcms.com/a/614202.html

相关文章:

  • 做网站建设培训wordpress如何添加网站地图
  • 网站关键词搜索排名优化郑州建设网站定制
  • Java输入输出:编程世界的入口和出口
  • Xcode编译C语言:提升编译效率与调试技巧
  • MONGO-EXPRESS Docker 容器化部署指南
  • 免费psd图片素材网站邯郸网站开发
  • IDEA配置Maven
  • 昆明做网站外包预定型网站有哪些
  • 深圳建设工程交易中心网站百度链接提交地址
  • 《中医基础理论》- 2.哲学基础之藏象学说-肾系统详解
  • 绍兴网站建设方案响应式网站建设报价单
  • 采用Langchain调用LLM完成简单翻译任务
  • 游戏网站建设流程图注册一个电商公司需要多少钱
  • 深度拥抱变革:AI 重塑临床工作流与医院信息化的战略蓝图与实施路线
  • 北京网站制作公司招聘淘宝客网站备案
  • 服务器开荒:安装宝塔面板
  • 基于AWS的应用程序可靠性提升架构优化方案——RDS多可用区与EC2弹性架构实践
  • 数据库事务ACID特性详解
  • 基于单片机的自行车速度与里程检测报警系统设计
  • 网站运营计划书建筑费用明细表模板
  • GPT-5.1发布!你的AI更暖更智能!
  • 万悉科技GEO专题分享会——共探AI时代中国出海企业的流量新机遇
  • 商业网站的相关内容青岛网站设计网站
  • Python判断字符串中是否有中文
  • 前端动画技术发展方向
  • 图片网站该如何做seo优化万户网络做网站怎么样
  • qt显示类控件---QLCDNumber
  • C#1115变量
  • 钓鱼网站排名假冒建设银行最多wordpress停止更新
  • 思维链(CoT)的本质:无需架构调整,仅靠提示工程激活大模型推理能力