Go 语言学习一篇入门

news2024/12/23 14:34:08

Goloang的优缺点

Goloang的优点

极其简单的部署方式

  • 可直接编译成机器码
  • 不依赖其他库
  • 直接运行即可部署

语言层面的并发

  • 天生的基因支持
  • 充分的利用多核

强大的标准库

  • runtime 系统调度机制
  • 高效的GC垃圾回收
  • 丰富的标准库

Goloang的不足

  • 包管理,大部分包都在github
  • 无泛化类型(Golang 1.18+已经支持泛型)
  • 所有Excepiton都用Error来处理(比较有争议)。
  • C的降级处理,并非无缝,没有C降级到asm那么完美(序列化问题)

关于编译运行

package main//包含 main 函数的一定要包这个

// import "fmt"
// import "time"

import(
	"fmt"
	"time"
)

func main(){//函数的 { 一定是和函数名在同一行的这是语法规定,不然有编译错误
	fmt.Println("hello Go!")//可;可不;
	fmt.Print("hello Go!\n")

	time.Sleep(1*time.Second);
}

01. 变量

//变量
func main(){
	//1.默认
	var a int
	var aa,bb int = 100,"fasgds"
	fmt.Println("a=",a)//a=0
	//2.初始化
	var b int=100
	fmt.Printf("b=%d,type of b=%T\n",b,b);
	//3.初始化的时候自动推导
	var c = 12.6
	fmt.Printf("c=%f,type f c=%T\n",c,c);
	//4.(常用)省区var 直接自动匹配 —— 但是只能用在函数体内,全局不可以
	d:=1000
	fmt.Println("d=",d)
	fmt.Printf("type of d=%T\n",d);
	time.Sleep(1*time.Second);
}

0.2 常量

但是iota只能在const()里面使用,进行累加效果

go可以多参数返回(返回值可以形参的形式或者直接return多个值)

0.3 defer

defer——defer就相当于析构函数,并且执行在return之后

04. 数组

go的数组,但是定长数组传参很麻烦,只能是形参声明的特定的那一个长度,而且是值拷贝

05. 动态数组slice

go的动态数组 slice(切片)

slice的声明方式

slice使用方式

1. 切片容量的增加(扩容 5->10->20)

2. 切片容量的截取

06. map

go的map声明方式

go的map使用方式(传参的时候和slice一样是引用传参)

07. struct

struct的基本定义与使用

和typedef相似

08. go中类的表示与封装

但是大小写,对本包没有区别

//封装
type Hero struct{
	nAme string
	Sex string
	Lv int
}

func (this* Hero) GetName()string{
	fmt.Println("Name=",this.nAme);
	return this.nAme
}

func (this* Hero)SetName(name string){
	this.nAme=name
}

func main(){
	hero := Hero{nAme:"zhangsan",Sex:"nan",Lv:7}
	hero.GetName()
	hero.SetName("lisi")

	fmt.Println(hero)
}

09. go的继承

//继承
type Animal struct{
	sex string
	age int
}

type Cat struct{
	Animal //-------------直接把要继承的类名写下来就可以了
	color string//猫的颜色
}

func (this* Cat) SetCat(sex string,age int,color string)  {
	this.sex=sex
	this.age=age
	this.color=color
}

func (this* Cat) ShowCat(){
	fmt.Println("cat sex:",this.sex," cat age",this.age," cat color",this.color)
}

func (this* Cat) GetCatColor() string {
	//fmt.Println(this.color)
	return this.color
}

func main(){
	var cat Cat
	cat.color="blue"

	cat.SetCat("nv",3,"yel")
	cat.ShowCat()
	// var ret = cat.GetCatColor()
	// fmt.Println(ret)
	// fmt.Println("--------")
}

10. go的多态

go的多态就是需要先有一个 interface 的接口,这里面就放需要多态的方法,子类去重写的时候不需要像cpp一样继承,直接重写就相当于继承了,但是注意一定要把接口全部重写才可以。

//多态
type AnimalIF interface{
	Sleep()
	GetColor() string//获取动物颜色
	GetType() string//获取动物类型
}

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

func (this* Cat)Sleep(){
	fmt.Println("cat is sleep")
}

func (this* Cat)GetColor()string{
	return this.color
}

func (this* Cat)GetType()string{
	return "Cat"
}

//-----------

type Dog struct{
	color string//狗的颜色
}

func (this* Dog)Sleep(){
	fmt.Println("dog is sleep")
}

func (this* Dog)GetColor()string{
	return this.color
}

func (this* Dog)GetType()string{
	return "Dog"
}

//法二:
func ShowAnimal(animal AnimalIF/*接口的数据类型,父类指针*/){
	animal.Sleep()
	fmt.Println("animal color:",animal.GetColor())
	fmt.Println("animal type",animal.GetType())
}

func main(){
	//法一:
	// var animal AnimalIF//接口的数据类型,父类指针
	// animal = &Cat{"blue"} //注意&
	// animal.Sleep()
	// animal = &Dog{"yel"}
	// animal.Sleep()	
	//法二: 运用统一的方法去调用
	cat := Cat{"blue"}
	dog := Dog{"yel"}
	ShowAnimal(&cat)
	ShowAnimal(&dog)
}

11. interface

interface空接口万能类型与类型断言机制(三种作用:定义一般的普通接口(多态),空接口(万能接口),进行断言(判断类型,与万能接口配套用))

断言:断言有两步,一:得到动态类型type,二:判断type是否实现了目标接口。

arg.(string):判断此时arg指向的变量是否是string类型的(称为类型断言)

变量的内置pair结构详细说明

就是任何一个变量,里面都是有一个pair,称 type 和 value,type里面有两种,只能选其一,一个是属于 static type(像int,string),另一个是 concrete type(具体类型,就是interface所指向的具体类型,这种类型是系统看得见的类型)

关于pair再一个例子:就是打开了一个文件描述符,然后赋值给io里面的读变量和写变量,赋值的过程中,pair里面所存储的数据是不会变的(文件描述符指针类型,和指向的文件描述符),然后是把打开的tty(终端),赋值给了r(读方法),再将 r 赋值(w=r.(io.Writer)是r先强制转换为Writer,然后赋值给我)给w,然后用w去写数据到终端

12. go反射reflect机制用法

反射的两个重要接口,反射就是为了获取当前变量的type和value

基本类型反射

复杂类型反射

package main

import (
	"fmt"
	"reflect"
)

type User struct{
	Id int
	Name string
	Age int
}

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

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

	DoFiledAndMethod(user)
}

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

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

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

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

13. go反射解析结构体标签Tag

这个玩意就是相当于注释或者mysql的comment

关于标签的使用:是键盘1左边的按键``,然后里面是

key value(例子: `key1:"value1"` `key2:"value2"`)

(取标签的时候key肯定是已知的,通过协议定制的)

结构体标签在json中的运用

发现json解析出来的结果就是我们刚才标签里面设置的内容

13. goroutine

创建goroutine(直接 go 一个方法就可以了,和进程线程一样,当main goroutine结束的时候,子goroutine也结束)

在一个 go routine 里面提前退出

14. channel(专门用来提供goroutine直接相互通信的)(类似之前的IPC通信)

1. channel的定义

2. channal有缓冲与无缓冲同步问题

(make(chan int,3)这里的3如果没有就是没有缓冲)

对于下面的打印顺序我们是无法保证的,但是“子go程结束”一定是“num=0”之后

3. channal的关闭特点

这里没有对channal进行关闭,导致goroutine执行完之后报错了

4. channal和range

这个代码就是,range尝试去c中读数据,c中如果有数据,就等待c的结果,有了就给data,然后进行一次for循环,等待 goroutine close 之后,和退出for循环

5. channal与select(相当于多路转接)

几个case,就是监听几个channal

15. Go Modules模式

GOPATH工作模式有一些弊端,下载使用Go Modules模式

Go Modules模式基础环境说明(go 1.11以上才可以用)

go mod 命令

go env -w GO111MODULE=on(设置之后go mod 模式就会生效)

(之前导包需要手动下载,现在有go mod之后只需要在代码中写上import的github路径,就会自动在github上面帮我们下载这个包,GPPOXY就代表我们从哪个第三方托管平台去下载)

go env -w GOPROXY=https://goproxy.cn,direct(博主设置的七牛云的/export GOSUMDB=sum.golang.org)(多了个direct是指:当当前配置的地方拉取不到需要的包,就会指示go重定向到源地址去抓取)

GoModules 初始化项目

(如果是用原来的方法导入,就需要cd $GOPATH/src ,到指定位置 go get .../name)

首先在需要go mod 的模块进行初始化 

go mod init github.com/sder/moudles_test(后面跟的这个名称就是后面其他人使用的时候 import导入的名称)(生成了go.mod就说明初始化成功了,然后就可以正常写代码了)

package main

import (
	"fmt"
	"github.com/aceld/zinx/ziface"
	"github.com/aceld/zinx/znet"
)

// PingRouter MsgId=1 
type PingRouter struct {
	znet.BaseRouter
}

//Ping Handle MsgId=1
func (r *PingRouter) Handle(request ziface.IRequest) {
	//read client data
	fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
}

func main() {
	//1 Create a server service
	s := znet.NewServer()

	//2 configure routing
	s.AddRouter(1, &PingRouter{})

	//3 start service
	s.Serve()
}

就像博主这样,导入了两个包,里面有很多这两个包的方法,直接运行是不可以的,然后我们现在只需要:

把需要用到的,也就是代码里面 import 的

go get github.com/aceld/zinx/ziface

go get github.com/aceld/zinx/znet

导入之后我们的gomod就多了我们需要的包以及版本信息(indirect表示间接依赖,就是说只用了需要包的一部分,并不是需要用到整个包),同时还多了一个go.sum文件

对于go.sum里面,h1:加上hash值代表hash了整个包,验证整个包的完整性

go.mod加上hash,表示的是这个mod文件的hash值

而我们现在的库是给我们下载到了 $GOPATH/pkg/mod

这个文件夹里面就有当前的模块名

现在这种方式就可以在任何地方不用一定把当前项目放在 $GOPATH/src 路径中,现在只需要把go mod 加上 ,指定使用哪个包,然后 go get 包就可以了

修改项目mudule指定版本的依赖关系

16. Go项目——及时通信系统

main.go

package main


func main(){
	server := NewServer("127.0.0.1",8080)
	server.Start()
}

user.go

package main

import (
	"net"
	"strings"
)

type User struct{
	Name string
	Addr string
	C chan string //用来接收广播消息
	conn net.Conn //socket通信的连接

	server *Server//当前用户所属的server
}

//创建一个用户的API
func NewUser(conn net.Conn,server *Server) *User{
	userAddr := conn.RemoteAddr().String()

	user := &User{
		Name: userAddr,
		Addr: userAddr,
		C: make(chan string),
		conn: conn,
		server: server,
	}

	//启动当前user channal消息的goroutine
	go user.ListenMessage()

	return user
}

//用户上线的业务
func (this *User) Online(){
	//用户上线,将用户加入到onlineMap中
	this.server.mapLock.Lock()
	this.server.OnLineMap[this.Name] = this
	this.server.mapLock.Unlock()

	//广播用户上线消息
	this.server.BroadCast(this, "已上线")
}

//用户下线的业务
func (this *User) Offline(){
	//用户下线,将用户从onlineMap中删除
	this.server.mapLock.Lock()
	delete(this.server.OnLineMap, this.Name)
	this.server.mapLock.Unlock()

	//广播用户下线消息
	this.server.BroadCast(this, "已下线")
}

//给当前User对应的客户端发送消息
func (this *User) SendMsg(msg string){
	this.conn.Write([]byte(msg))
}

//用户发送消息的业务
func (this *User) DoMessage(msg string){
	if msg == "who"{
		//查询当前在线用户
		this.server.mapLock.Lock()
		for _, user := range this.server.OnLineMap{
			onlineMsg := "[" + user.Addr + "]" + user.Name + ": 在线...\n"
			this.SendMsg(onlineMsg)
		}
		this.server.mapLock.Unlock()
	}else if len(msg) > 7 && msg[:7] == "rename|"{//rename|张三
		//消息格式:rename|张三
		newName := strings.Split(msg, "|")[1]
		//判断name是否存在
		_, ok := this.server.OnLineMap[newName]
		if ok{
			this.SendMsg("当前用户名被使用\n")
		}else{
			this.server.mapLock.Lock()
			delete(this.server.OnLineMap, this.Name)
			this.server.OnLineMap[newName] = this
			this.server.mapLock.Unlock()

			this.Name = newName
			this.SendMsg("您已经更新用户名:" + this.Name + "\n")
		}
	}else if len(msg) > 4 && msg[:3] == "to|"{
		//消息格式:to|张三|消息内容
		remoteName := strings.Split(msg, "|")[1]
		if remoteName == ""{
			this.SendMsg("消息格式不正确,请使用\"to|张三|消息内容\"格式\n")
			return
		}
		//根据用户名得到对方User对象
		remoteUser, ok := this.server.OnLineMap[remoteName]
		if !ok{
			this.SendMsg("该用户名不存在\n")
			return
		}
		//获取消息内容,通过对方的User对象将消息内容发送过去
		content := strings.Split(msg, "|")[2]
		if content == ""{
			this.SendMsg("无消息内容,请重发\n")
			return
		}
		remoteUser.SendMsg(this.Name + "对您说:" + content + "\n")
	}else{
		this.server.BroadCast(this, msg)
	}
}

//监听当前User channal的方法,一旦有消息,就直接发送给对端客户端
func (user *User) ListenMessage(){
	for{
		msg := <- user.C
  		user.conn.Write([]byte(msg + "\n"))
	}
}

server.go

package main

import(
	"fmt"
	"net"
	"sync"
	"time"
)

type Server struct{
	Ip string
	Port int

	//在线用户列表
	OnLineMap map[string]*User
	mapLock sync.RWMutex

	//消息广播的channel
	Message chan string
}

//创建一个server的接口
func NewServer(ip string, port int) *Server{
	server := &Server{
		Ip: ip,
		Port: port,

		OnLineMap: make(map[string]*User),
		Message: make(chan string),
	}
	return server
}  

//监听Message广播消息channal的goroutine,一旦有消息就发送给全部的在线User
func (this *Server)ListenMessage(){
	for{
		msg := <-this.Message
		//将msg发送给全部的在线User
		this.mapLock.Lock()
		for _,cli := range this.OnLineMap{
			cli.C <- msg
		}
		this.mapLock.Unlock()
	}
}

//广播用户上线消息的方法
func (this *Server) BroadCast(user *User, msg string){
	sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg

	this.Message <- sendMsg
}



func (this *Server) Handler(conn net.Conn){
	//fmt.Println("connect success")

	user := NewUser(conn,this)

	user.Online()

	//监听用户是否活跃的chananl
	isLive := make(chan bool)

	//接受客户端发送的消息
	go func(){
		buf := make([]byte, 4096)
		for{
			n, err := conn.Read(buf)
			if n == 0{
				user.Offline()
				return
			}
			if err != nil && n == 0{
				fmt.Println("conn read error", err)
				return
			}

			//提取用户的消息,去除'\n'
			msg := string(buf[:n-1])
			
			//用户针对msg进行消息处理
			user.DoMessage(msg)

			//用户的任意消息,代表当前用户是活跃的
			isLive<-true
		}
	}()
	//当前handler阻塞
	for{
		select {
			case<-isLive:
				//当前用户是活跃的,应该重置定时器
				//不做任何事情,为了激活select,更新下面的定时器
			case <-time.After(time.Second*5):
				//用户已经超时
				//当前的User应该强制关闭	
				user.SendMsg("你被踢了")
				//销毁用的资源
				close(user.C)
				//关闭连接
				conn.Close()
				//退出当前的Handler

				return//runtime.Goexit()
		}
	}
}

//启动服务器的方法
func (this *Server) Start(){
	//socket listen
	listener,err := net.Listen("tcp",fmt.Sprintf("%s:%d",this.Ip,this.Port))
	if err != nil{
		fmt.Println("listen error", err)
		return
	}
	//Close listener socket
	defer listener.Close()

	//启动监听的goutine
	go this.ListenMessage()	

	//accept
	for{
		conn, err := listener.Accept()
		if err != nil{
			fmt.Println("accept error", err)
			continue
		}
		//do handler
		go this.Handler(conn)
	}
}

client.go

package main

import (
	"fmt"
	"net"
	"flag"
	"io"
	"os"
)

type Client struct{
	ServerIp string
	ServerPort int
	Name string
	conn net.Conn
	flag int//当前client的模式
}

//创建客户端
func NewClient(serverIp string,serverPort int) *Client{
	//创建客户端对象
	client := &Client{
		ServerIp: serverIp,
		ServerPort:serverPort,
		flag:999,
	}

	//链接server	
	conn,err := net.Dial("tcp",fmt.Sprintf("%s:%d",serverIp,serverPort))
	if err!=nil{
		fmt.Println("net Dial error:",err)
		return nil
	}

	client.conn =conn

	//返回对象
	return client
}

//处理server回应的消息,直接显示在标准输出
func (client *Client) DealResponse(){
	//一旦client.conn有数据,就直接copy到stdout标准输出上,永久阻塞监听
	io.Copy(os.Stdout,client.conn)
	//等价于
	//for{				
	//	buf := make([]byte,4096)
	//	n,err := client.conn.Read(buf)
	//	fmt.Println(string(buf[:n]))
	//}
}

func (client *Client) menu()bool{
	var flag int

	fmt.Println("1.公聊模式")
	fmt.Println("2.私聊模式")
	fmt.Println("3.更改用户名")
	fmt.Println("0.退出")

	fmt.Println("请输入指令:")
	fmt.Scanln(&flag)

	if flag >= 0 && flag <= 3{
		client.flag = flag
		return true
	}else{
		fmt.Println(">>>请输入正确的指令")
		return false
	}

}

//查询在线用户
func (client *Client) SelectUsers(){
	sendMsg := "who\n"
	_,err := client.conn.Write([]byte(sendMsg))
	if err!=nil{
		fmt.Println("conn Write error:",err)
		return
	}
}

//私聊模式
func (client *Client) PrivateChat(){
	client.SelectUsers()

	fmt.Println(">>>请输入聊天对象[用户名],exit退出:")
	var remoteName string
	fmt.Scanln(&remoteName)

	for remoteName != "exit"{
		fmt.Println(">>>请输入消息内容,exit退出:")
		var chatMsg string
		fmt.Scanln(&chatMsg)
		for chatMsg != "exit"{
			//消息不为空
			if len(chatMsg) != 0{
				//消息不为空
				sendMsg := "to|" + remoteName + "|" + chatMsg + "\n"
				_,err := client.conn.Write([]byte(sendMsg))
				if err!=nil{
					fmt.Println("conn Write error:",err)
					break
				}
			}
			
			chatMsg = ""
			fmt.Println(">>>请输入消息内容,exit退出:")
			fmt.Scanln(&chatMsg)
		}
		client.SelectUsers()
		fmt.Println(">>>请输入聊天对象[用户名],exit退出:")
		fmt.Scanln(&remoteName)
	}
}

//共聊模式
func (client *Client) PublicChat(){
	//提示用户输入消息
	var chatMsg string
	fmt.Println(">>>请输入聊天内容,exit退出")
	fmt.Scanln(&chatMsg)
	for chatMsg != "exit"{
		//发送给服务器
		if len(chatMsg) != 0{
			_,err := client.conn.Write([]byte(chatMsg + "\n"))
			if err!=nil{
				fmt.Println("conn Write error:",err)
				break
			}
		}
	
		chatMsg = ""
		fmt.Println(">>>请输入聊天内容,exit退出")
		fmt.Scanln(&chatMsg)
	}
}

//客户端版的更新用户名
func (client *Client) UpdateName()bool{
	fmt.Println(">>>请输入用户名:")
	fmt.Scanln(&client.Name)

	sendMsg := "rename|" + client.Name + "\n"
	_,err := client.conn.Write([]byte(sendMsg))
	if err!=nil{
		fmt.Println("conn Write error:",err)
		return false
	}

	return true
} 

func (client *Client) Run(){
	for client.flag != 0{
		//判断当前客户端的模式如果非法输入就一直死循环
		for client.menu() != true{
		}
		switch client.flag{
		case 1:
			//公聊模式
			fmt.Println(">>>公聊模式")
			client.PublicChat()
			break
		case 2:
			//私聊模式
			fmt.Println(">>>私聊模式")
			client.PrivateChat()
			break
		case 3:
			//更改用户名
			fmt.Println(">>>更改用户名")
			client.UpdateName()
			break
		}
	}
}

var serverIp string
var serverPort int

//./client -ip 127.0.0.1 -port 8080
//init操作就是把这两个形参绑定到flag这个包中
func init(){
	//flag库运行我们绑定命令行参数 第二个参数就是上面的 -ip 第三个是默认值 
	//第四个是用户输入 ./client -h(help)的时候的提升
	flag.StringVar(&serverIp,"ip","127.0.0.1","设置服务器IP地址(默认为127.0.0.1)")
	flag.IntVar(&serverPort,"port",8080,"设置服务器端口(默认是8080)")
}

func main(){
	//命令行解析
	flag.Parse()

	client := NewClient(serverIp,serverPort)
	if client == nil{
		fmt.Println(">>>连接服务器失败....")
		return
	}

	//单独开启一个goroutine处理server的回执消息
	go client.DealResponse()

	fmt.Println(">>>连接服务器成功...")

	//启动客户端的业务
	client.Run()
}

本文根据小破站作者 刘丹冰Aceld 8小时专职Go 所著

在此感谢该博主讲的很棒! 

最后的最后,创作不易,希望读者三连支持 💖
赠人玫瑰,手有余香 💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1559892.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MultiPath HTTP:北大与华为合作部署FLEETY

当前的终端基本都能支持蜂窝网络和wifi网络&#xff0c;然而&#xff0c;不同的网络通路都不可避免的会出现信号不好或者其他因素引起的通路性能(吞吐量、时延等)下降。为了能够提升终端业务体验&#xff0c;很多不同的MultiPath方案被提出&#xff0c;其中&#xff0c;包括应用…

(文章复现)考虑分布式电源不确定性的配电网鲁棒动态重构

参考文献&#xff1a; [1]徐俊俊,吴在军,周力,等.考虑分布式电源不确定性的配电网鲁棒动态重构[J].中国电机工程学报,2018,38(16):4715-47254976. 1.摘要 间歇性分布式电源并网使得配电网网络重构过程需要考虑更多的不确定因素。在利用仿射数对分布式电源出力的不确定性进行合…

Decoupled Multimodal Distilling for Emotion Recognition 论文阅读

Decoupled Multimodal Distilling for Emotion Recognition 论文阅读 Abstract1. Introduction2. Related Works2.1. Multimodal emotion recognition2.2. Knowledge distillation3. The Proposed Method3.1. Multimodal feature decoupling3.2. GD with Decoupled Multimodal …

【Gd2O3】Gd2O3栅极电介质增强GaN器件的可靠性

【Effects of Gd2O3 Gate Dielectric on Proton-Irradiated AlGaN/GaN HEMTs】 概括总结&#xff1a; 该研究探讨了质子辐射对使用Gd2O3作为栅极电介质的AlGaN/GaN高电子迁移率晶体管&#xff08;HEMTs&#xff09;的影响。通过对比肖特基栅极HEMTs和MOS-HEMTs在2 MeV质子辐射…

SOC内部集成网络MAC外设+ PHY网络芯片方案:MII/RMII 接口与 MDIO 接口

一. 简介 本文来了解一下常用的一种网络硬件方案&#xff1a;SOC内部集成网络MAC外设 PHY网络芯片方案。 其中涉及的 MII接口&#xff0c;RMII接口&#xff08;MII接口与RMII接口二选一&#xff09;&#xff0c;MDIO接口&#xff0c;RJ45。 二. MII/RMII 接口&#xff0c;M…

数据挖掘|贝叶斯分类器及其Python实现

分类分析|贝叶斯分类器及其Python实现 0. 分类分析概述1. Logistics回归模型2. 贝叶斯分类器2.1 贝叶斯定理2.2 朴素贝叶斯分类器2.2.1 高斯朴素贝叶斯分类器2.2.2 多项式朴素贝叶斯分类器 2.3 朴素贝叶斯分类的主要优点2.4 朴素贝叶斯分类的主要缺点 3. 贝叶斯分类器在生产中的…

随便注【强网杯2019】

大佬的完整wp&#xff1a;buuctf-web-[强网杯 2019]随便注-wp_取材于某次真实环境渗透,只说一句话:开发和安全缺一不可-CSDN博客 知识点&#xff1a; 单引号字符型绕过堆叠注入 可以执行多条语句multi_query()&#xff1a;该函数可能引发堆叠注入handler用法 mysql专属&#…

面试题:JVM 调优

一、JVM 参数设置 1. tomcat 的设置 vm 参数 修改 TOMCAT_HOME/bin/catalina.sh 文件&#xff0c;如下图 JAVA_OPTS"-Xms512m -Xmx1024m" 2. springboot 项目 jar 文件启动 通常在linux系统下直接加参数启动springboot项目 nohup java -Xms512m -Xmx1024m -jar…

动态内存管理-错题合集讲解

空指针的解应用操作&#xff08;错误信息合集&#xff09; 越界访问 首先我们上一个代码&#xff0c;看看这个的代码的问题 这个代码的问题显而易见 &#xff0c;就是在循环里面&#xff0c;产生了越界访问的问题&#xff0c;这里你开辟了10个整形空间&#xff0c;但是从0-1…

谈谈MVCC机制

在MySQL中&#xff0c;MVCC&#xff08;多版本并发控制&#xff09;是InnoDB存储引擎使用的并发控制机制。它提供对数据的并发访问&#xff0c;并确保多用户环境中数据的一致性和隔离性。 InnoDB通过“Undo log”存储每条记录的多个版本&#xff0c;提供历史记录供读取&#x…

Python数据结构与算法——数据结构(链表、哈希表、树)

目录 链表 链表介绍 创建和遍历链表 链表节点插入和删除 双链表 链表总结——复杂度分析 哈希表(散列表) 哈希表介绍 哈希冲突 哈希表实现 哈希表应用 树 树 树的示例——模拟文件系统 二叉树 二叉树的链式存储 二叉树的遍历 二叉搜索树 插入 查询 删除 AVL树 …

后端SpringBoot+Mybatis 查询订单数据库奇怪报错加一

排错过程&#xff1a; 看报错意思是SQL语句存在错误&#xff0c;然后使用图形化工具运行这个SQL语句 其实这里稍微细心想一下就能发现问题&#xff0c;但是当时没深入想&#xff0c;就觉得order表前加了数据库名字影响不大&#xff0c;所以感觉SQL语句是没问题的&#xff0c;然…

Java6升级至Java8常用新特性

目录 Java 8 常用新特性1、Lambda 表达式2、方法引用2.1 静态方法引用2.2 特定对象的实例方法引用2.3 特定类型的任意对象的实例方法引用2.4 构造器引用 3、接口中的默认方法4、函数式接口4.1 自定义函数式接口4.2 内置函数式接口 5、Date/Time API6、Optional 容器类型7、Stre…

【Qt】窗口

目录 一、概述二、菜单栏&#xff08;QMenuBar&#xff09;三、工具栏&#xff08;QToolBar&#xff09;四、状态栏&#xff08;QStatusBar&#xff09;五、浮动窗口六、对话框 一、概述 Qt窗口是通过QMainWindow类来实现的。 QMainWindow是一个为用户提供主窗口程序的类&…

程序数据模型由OS还是硬件架构决定?

文章目录 前言硬件架构的作用OS的作用编译器的角色OS的数据模型参考 前言 在文章 1>>32的结果是1还是0 中提到了数据模型 L P 64 LP64 LP64 &#xff0c;并提出这个数据模型主要是由 U n i x Unix Unix 以及类 U n i x Unix Unix 的操作系统使用居多&#xff0c;例如…

SpringBoot 缓存预热

简介&#xff1a; SpringBoot集合RedisUtil和 CommadnLinRunner实现缓存预热 一、新建一个缓存抽象类 在redis模块里面 新建 /*** 缓存抽象类*/ Component public abstract class AbstractCache {// 初始化缓存public void initCache() {}public <T> T getCache(Strin…

虚拟现实(VR)项目的开发工具

虚拟现实&#xff08;VR&#xff09;项目的开发涉及到多种工具&#xff0c;这些工具可以帮助开发者从建模、编程到最终内容的发布。以下是一些被广泛认可的VR开发工具&#xff0c;它们覆盖了从3D建模到交互设计等多个方面。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

PySpark的学习

一. 什么是PySpark 使用过的bin/pyspark 程序 , 要注意 , 这个只是一个 应用程序 , 提供一个 Python 解释器执行环境来运行 Spark 任务 现在说的 PySpark, 指的是 Python 的运行类库 , 是可以在 Python 代码中 :import pyspark PySpark 是 Spark 官方提供的一个 Python …

MP设置动态表名

Mybatis设置动态表名 Mybatis设置动态表名1.动态表名插件2.传递表名3.注意事项 Mybatis设置动态表名 1.动态表名插件 MybatisPlus中提供了一个动态表名的插件&#xff1a;https://baomidou.com/pages/2a45ff/#dynamictablenameinnerinterceptor 插件的部分源码如下&#xff…

【SpringCloud】Eureka注册中心

目 录 一.Eureka的结构和作用二.搭建 eureka-server1. 创建 eureka-server 服务2. 引入 eureka 依赖3. 编写启动类4. 编写配置文件5. 启动服务 三.服务注册1. 引入依赖2. 配置文件3. 启动多个user-service实例 四.服务发现1. 引入依赖2. 配置文件3. 服务拉取和负载均衡 总结 假…