Go语言快速入门笔记

news2024/11/16 23:45:12

文章目录

    • import匿名导包和别名导包的方式
    • defer语句
    • 数组和动态数组
      • 固定长度数组
      • 切片(动态数组)
        • 切片的容量追加和截取
    • map
    • 面向对象
    • struct
      • 继承
      • 多态
      • interface空接口万能类型与类型断言机制
    • 变量的内置pair结构
      • 变量结构
      • reflect包(反射)
      • reflect反射解析结构体标签tag
    • Goroutine基本模型和调度设计策略
      • GMP
      • 调度器的设计策略
      • 创建Goroutine
    • channel机制
      • channel的定义和使用
      • 无缓冲的channel
      • 有缓冲的channel
      • channel的关闭
      • channel与range
      • channel与select
    • Go Modules
      • GOPATH
      • Go Modules模式
      • Go Modules初始化项目
        • 开启Go Modules
        • 项目初始化
      • 改变模块版本依赖关系

取自B站视频:https://www.bilibili.com/video/BV1gf4y1r79E

import匿名导包和别名导包的方式

import (
    _ "GolangStudy/lib1" //匿名导包,这样不适用这个包也不会报错
    mylib1 "GolangStudy/lib1" //别名导包,可以直接用mylib1
    . "GolangStudy/lib1" //直接把这个包导入本地包。比如调用xx()函数就不用lib1.xx()了,可以直接写xx()
)

defer语句

  • 一般用来最后销毁一些东西。多个defer定义的话会压栈,先进后出
  • 如果又有defer又有return语句,那么先return,最后执行defer
func main(){
	defer fmt.Println("main1 end.")
    defer fmt.Println("main2 end.")
	fmt.Println("1 end.")
	fmt.Println("2 end.")
}
//执行结果
1 end.
2 end.
main2 end.
main1 end.

数组和动态数组

固定长度数组

  • go语言中固定长度的数组和切片是两种类型,并不兼容
  • 长度也是固定长度数组类型中的一部分,函数传参时数组长度也要严格匹配
  • go语言中数组作为函数参数是值传递而不是引用传递
//固定长度数组
var myArray [10]int
myArray := [10]int{1,2,3,4} //golang中没有初始化的值默认为0
fmt.Printf("type: %T", myArray) //输出为:types: [10]int go中定长数组的长度也是类型中的一部分
func printArray(myArray [10]int){} //这个函数就只能接收长度为10的数组,不能接收其他长度的数组
func printArray(myArray []int){} //这个函数不能接收myArray,因为定长数组和切片是不同类型

func printArray(myArray [10]int){
    myArray[1] = 24 //这条语句不会影响传进来的原数组的值
}

切片(动态数组)

  • go语言中切片作为函数参数是引用传递而不是值传递(和固定长度数组做区分)
//切片
mySlice := []int{1,2,3} //声明并初始化一个长度为3的切片 
var mySlice []int //声明一个切片,但是并未分配空间
fmt.Printf("type: %T", mySlice) //输出为:types: []int
  • 注意slice的空间要分配了才能用,否则会出现越界错误
var mySlice []int 
mySlice[0] = 1 //由于前面slice并未被分配空间,因此直接访问下标会出现越界错误
mySlice = make([]int, 3) //这样就分配了长度为3的空间,默认值为0 
var mySlice2 = make([]int, 3) //切片的另一种定义方式

切片的容量追加和截取

  • 切片追加到超过容量时,容量会扩充为原来的两倍
  • 切片截取的本质是引用传递,修改截取后的切片值会同步修改原切片
  • 可以使用copy函数进行切片拷贝
var mySlice = make([]int, 3, 5) //定义一个长度为3,容量为5的切片
mySlice = append(mySlice, 1) //向切片中追加一个元素1,此时长度为4,容量为5
fmt.Printf("len=%d, cap=%d", len(mySlice), cap(mySlice)) //输出 len=4, cap=5
mySlice = append(mySlice, 1) //向切片中追加一个元素1,此时长度为5,容量为5

mySlice = append(mySlice, 1) //向切片中追加一个元素1,此时长度为6,容量为10

s1 := mySlice[0:2] //截取前两个元素,左闭右开,引用传递

map

  • go中的map是O(1)的无序结构
  • map作为函数参数是引用传递
var myMap map[string]string //声明map,并未实际分配空间
myMap = make(map[string]string, 10)  //分配空间,空间长度可省略

在这里插入图片描述

面向对象

struct

  • this有两种,一种是this指针,指向当前对象,第二种是this对象,是当前对象的一个拷贝

  • 方法名或成员名大写,表示其他包可以访问,否则只能在本包访问

    type Test struct{
        a int
        b string
    }
    func (this Test) SetA(c int){
        this.a = c //这时候这个类对象中的a并不会被更改,因为this只是一个对象的拷贝
    }
    func (this *Test) SetA(c int){
        this.a = c //这时这个类对象中的a会被修改为c,因为this是这个对象的指针
    }
    

继承

type Human struct{
	name string
	sex string
}
func (this *Human) Eat(){
    //...
}
type SuperMan struct{
	Human //SuperMan类继承了Human类的方法
    level int
}
//重定义父类的方法Eat()
func (this *SuperMan) Eat(){
    fmt.Println("SuperMan.Eat...")
}

多态

  • Go语言的类是没有多态的,多态靠接口(interface)实现
  • interface本质上是一个指针,可以指向具体实现的类
  • 只要一个类实现了某接口的全部方法,就认为是实现了该接口
package main

//接口,本质上是一个指针
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"
}
func main() {
	var animal AnimalIF
	animal = &Cat{"Green"}
}

interface空接口万能类型与类型断言机制

  • 空接口类型的参数可以接收任何类型,包括基本类型:int、string、float32等
  • 要具体区分传入的参数是什么类型可以通过类型断言
package main

import "fmt"

func myFunc(arg interface{}) {
	fmt.Println(("a ...interface{}"))

	value, ok := arg.(string)
	if !ok {
		fmt.Println("arg is not string type")
	} else {
		fmt.Println("arg is string type, value = ", value)
	}
}
type Book struct {
	auth string
}
func main() {
	book := Book{"Golang"}

	myFunc(book)
	myFunc(100)
	myFunc("abc")
	myFunc(3.14)
}

变量的内置pair结构

变量结构

  • 变量内置了一个pair结构,用于存储数据类型和值

  • 变量的结构

    • type指针
      • static type:int、string等基本类型
      • concrete type:interface所指向的具体数据类型,系统看得见的类型(运行时确定的类型)
    • value指针
  • 变量在赋值时,会同时把自己的pair结构赋值过来

package main

func main(){
    var a string
    //pair<statictype:string, value:"aceld">
    a = "aceld"
    
    //pair<type:string, value:""aceld>
    vra allType interface{}
    allType = a
}

reflect包(反射)

  • 通过reflect包提供的函数获取变量的类型和值

  • reflect包

    • ValueOf函数
    • TypeOf函数
func Valueof(i interface{}) Value {...}
func Typeof(i interface{}) Type {...}
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Id   int
	Name string
	Age  int
}

func (this *User) Call() {
	fmt.Println("user is called ..")
}

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

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

	inputValue := reflect.ValueOf(input)
	fmt.Println("inputValue is : ", inputValue)

	//通过type获取里面的字段
	//1. 获取interface的reflect.Type,通过Type得到NumField,进行遍历
	//2. 得到每个field,数据类型
	//3. 通过field的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)
	}
    for i := 0; i < inputType.NumMethod(); i++ {
		m := inputType.Method(i)
		fmt.Printf("%s: %v\n", m.Name, m.Type)

	}
}

reflect反射解析结构体标签tag

  • 每个结构体成员可以指定tag
  • tag可以用于json解析
package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)
type Movie struct {
	Title  string   `json:"title"`
	Year   int      `json:"year"`
	Price  int      `json:"rmb"`
	Actors []string `json:"actors"`
}

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)
    
	movie := Movie{"喜剧之王", 2000, 10, []string{"xingye", "zhangbozhi"}}
	//编码:将结构体编码为json的过程
	jsonStr, err := json.Marshal(movie)
	if err != nil {
		fmt.Println("json marshal error ", err)
		return
	}

	//解码:将json解码为结构体
	myMovie := Movie{}
	err = json.Unmarshal(jsonStr, &myMovie)
	if err != nil {
		fmt.Println("json unmarshal error ", err)
		return
	}

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

Goroutine基本模型和调度设计策略

  • Go的协程(goroutine)就是用户态线程,M个协程对应N的内核级线程,通过协程调度器来调度
  • 一个goroutine只有几kb,可以大量、灵活切换

在这里插入图片描述

  • 老版的调度器

    • 创建、销毁、调度G都需要每个M获取锁,这就形成了激烈的锁竞争
    • M转移G会造成延迟和额外的系统负载(当前G又创建了新的G)
    • 系统调用(CPU在M之间的切换)导致频繁的线程阻塞和取消阻塞操作增加了系统开销

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9DFs6ft-1669013131369)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121101734855.png)]

GMP

  • 一个P对应一个真正的内核线程
  • 一个P包含一个本地的goroutine等待运行队列
  • 全局队列存放一些等待运行的goroutine,如果本地队列满了的话就会放到全局队列中
  • 内核级的最大并发数量实际上是GOMAXPROCS

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jBZVRq2K-1669013131370)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121101415323.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poDIFqGA-1669013131371)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121101650404.png)]

调度器的设计策略

  • 复用线程

    • work stealing机制(工作窃取):当本地队列为空,可以从其他队列(其他本地队列或全局队列)窃取任务到本地队列中

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y7qU4F9u-1669013131372)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121102659710.png)]

    • hand-off机制:当正在执行的G1发生阻塞时,整个线程会被阻塞住。此时,再启动一个内核级线程,将当前本地队列挂到新的内核线程上,当前的G1继续在本地阻塞,执行完如果还要执行就加入其他队列中,否则销毁。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F3vuRRwL-1669013131373)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121103038447.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRGJB9Mt-1669013131377)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121103110453.png)]

  • 利用并行:通过GOMAXPROCS限定P的个数=CPU核数/2

  • 抢占:一个G最多10ms,时间片结束另一个G可以抢占

  • 全局G队列:

创建Goroutine

  • main goroutine退出,所有goroutine也会死亡
go func(){...}
runtime.Goexit() //该函数用于退出当前goroutine

channel机制

channel的定义和使用

  • channel本身是实现了同步互斥的模型机制的(阻塞等待保证同步互斥)

无缓冲的channel

  • 一次数据的发送和接收过程中两个goroutine都会被锁住,直到完全完成后两个goroutine才会被释放,可以执行其他任务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ko9cqvNZ-1669013131379)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121113341791.png)]

package main

import "fmt"

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

	go func() {
		for {
			defer fmt.Println("goroutine结束")
			fmt.Println("goroutine正在运行...")
			//由于是无缓冲channel,所以当c中数据未被消费时,此处会阻塞等待,直到channel为空再放入
			c <- 666 //将666 发送给c
		}
	}()
	i := 0
	for {
		i++
	}
	num := <-c //从c中接收数据,并赋值给num。等待是阻塞过程。
	fmt.Printf("receive num from channel c: %d\n", num)
	fmt.Println("main go routine 结束...")
}

有缓冲的channel

  • 两个goroutine发送和接收是异步的,发送完就可以执行其他任务,接收完也可以去执行其他任务,除非管道满或者空(与生产者-消费者模型类似)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hrauu5w3-1669013131380)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121113748162.png)]

package main

import (
	"fmt"
	"time"
)

func main() {
	//定义一个有缓冲channel
	c := make(chan int, 3)

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

	go func() {
		defer fmt.Println("goroutine结束")
		for i := 0; i < 3; i++ {
			c <- i
			fmt.Println("子go程正在运行,发送的元素=", i, " len(c)=", len(c), ", cap(c)=", cap(c))
		}
	}()
	time.Sleep(2 * time.Second)
	for i := 0; i < 3; i++ {
		num := <-c //从c中接收数据
		fmt.Println("num=", num)
	}
	fmt.Println("main go routine 结束...")
}

channel的关闭

  • 如果某goroutine一直等待channel的值,而没有goroutine再给channel写值,那么该goroutine会死锁,报错
  • 向关闭的channel发数据会引发panic
  • 关闭channel后,可以继续从channel接收数据
  • 对于nil channel,无论收发都会被阻塞
c := make(char int)
close(c) //关闭一个channel
if data, ok := <-c; ok {...} //判断channel是否为打开状态,若ok为true表示没有关闭(注意这个不是判断是否为空,而是是否打开)

channel与range

for data := range c {...}

channel与select

  • 单流程下一个go只能监控一个channel的状态,select可以完成监控多个channel的状态
  • select中哪个case先为真就执行哪个,都不为真就执行default
package main

import "fmt"

func fibonacii(c, quit chan int) {
	x, y := 1, 1
	for {
		select {
		//如果c可写
		case c <- x:
			tmp := y
			y = x + y
			x = tmp
		case <-quit: //如果quit可读
			fmt.Println("quit")
			return
		}
	}
}
func main() {
	c := make(chan int)
	quit := make(chan int)

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

		quit <- 0
	}()

	fibonacii(c, quit) //channel是引用传递
}

Go Modules

GOPATH

  • 目录结构

    • bin:一些编译好的二进制文件
    • pkg:一些依赖包之类的
    • src:自己写的go源代码
  • 弊端

    • 没有版本控制概念

      go get -u github.com/xxx //不能拉取指定版本,只拉取最新
      
    • 无法同步一致第三方版本号:不同的go项目,引用的相同库的版本无法一致

    • 无法指定当前项目引用的库版本号

Go Modules模式

  • 建议为了和GOPATH分开,不要将源码创建在GOPATH/src下

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ngnsGGbH-1669013131383)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121135209619.png)]

  • GO111MODULE:该环境变量为Go modules的开关

    • auto:只要项目包含了go.mod文件就启用Go Modules(在Go1.11至Go1.14中仍然是默认值)
    • on:启用
    • off:禁用
    go env -w GO111MODULE=on
    
  • GOPROXY:该环境变量用于设置Go模块代理,其作用是用于使Go在后续拉取模块版本时直接通过镜像站点来快速获取(以前是手动下载,现在自动到GOPROXY下载)

    GOPROXY="https//goproxy.cn,direct" #这个direct表示默认去该网址拉取,如果该网址找不到则去包指定网址拉取
    import "githubs.com/xxx.json" #比如这个会先去GOPROXY拉取,否则去github上拉
    
  • GOSUMDB:它的值是一个Go checksum database,用于在拉取模块版本时保证拉取到的模块版本数据未经过篡改,若发现不一致,也就是可能存在篡改,将会立即中止。你在本地对依赖进行变动(更新/添加)操作时,Go 会自动去这个服务器进行数据校验,保证你下的这个代码库和世界上其他人下的代码库是一样的。和go.mod一样,Go 会帮我们维护一个名为go.sum的文件,它包含了对依赖包进行计算得到的校验值。如果你的代码仓库或者模块是私有的,那么它的校验值不应该出现在互联网的公有数据库里面,但是我们本地编译的时候默认所有的依赖下载都会去尝试做校验,这样不仅会校验失败,更会泄漏一些私有仓库的路径等信息,我们可以使用GONOSUMDB这个环境变量来设置不做校验的代码仓库, 它可以设置多个匹配路径,用逗号相隔。举例:

    GONOSUMDB=*.corp.example.com,rsc.io/private
    
  • GOPRIVATE:go 命令会从公共镜像 http://goproxy.io 上下载依赖包,并且会对下载的软件包和代码库进行安全校验,当你的代码库是公开的时候,这些功能都没什么问题。但是如果你的仓库是私有的怎么办呢?

    环境变量 GOPRIVATE 用来控制 go 命令把哪些仓库看做是私有的仓库,这样的话,这些库会从私有仓库地址去拉取,并且跳过 proxy server 和校验检查(设置了GOPRIVATE之后,可以不用再设置GONOSUMDB和GONOPROXY),这个变量的值支持用逗号分隔,可以填写多个值,例如:

    GOPRIVATE=*.corp.example.com,rsc.io/private
    

    这样 go 命令会把所有包含这个后缀的软件包,包括 http://git.corp.example.com/xyzzy , http://rsc.io/private, 和 http://rsc.io/private/quux 都以私有仓库来对待。

Go Modules初始化项目

开启Go Modules

go env -w GO111MODULE=on
或者
export GO111MODULE=on

项目初始化

  • 注意尽量不要在GOPATH/src创建,否则可能有冲突
  • go get默认下载到$GOPATH/pkg/mod下面
  • go mod init github.com/aceld/modules_test,后面github.com/xxx是给当前项目起的模块名称,也可以不加。此时本目录会多一个go.sum文件。go.sum文件罗列当前项目直接或间接依赖的所有模块的版本,保证今后项目依赖的版本不会被篡改
  • 在拉取依赖包之后,会多一个go.sum文件
mkdir module_test
cd module_test

#初始化Go Modules,自动创建go.mod
go mod init github.com/aceld/modules_test #后面指定模块名称,别人就可以通过这一串来import这个模块

#创建main.go文件,写代码,导入一些包
go get xxx #下载导入的包,默认下载到$GOPATH/pkg/mod下
#也可以自动下载

改变模块版本依赖关系

  • go.mod中require中指定了包的依赖版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fUzowbMe-1669013131384)(C:\Users\12610\AppData\Roaming\Typora\typora-user-images\image-20221121143659656.png)]

  • 将xxx版本替换为yyy版本
go mod edit -replace=xxx=yyy

在这里插入图片描述

`

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

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

相关文章

【Java毕设】基于idea Java的在线考试系统(附源码+课件)

项目介绍&#xff1a; 本系统是一个基于java的在线考试系统。它的用户由学生、教师和系统管理员组成。学生登陆系统可以进行在线测试和成绩查询。当学生登陆时&#xff0c;系统会随机地为学生选取试题组成考卷。当学生提交考卷后&#xff0c;系统会自动批改客观题&#xff0c;…

html实现爱情告白(附源码)

文章目录1.设计来源1.1 主界面1.2 执子之手&#xff0c;与子偕老1.3 死生契阔&#xff0c;与子成说1.4 生当复来归&#xff0c;死当长相思1.5 自君之出矣&#xff0c;明镜暗不治1.6 思君如流水&#xff0c;何有穷已时1.7 南有乔木&#xff0c;不可休思1.8 汉有游女&#xff0c;…

快递查询工具,一键查物流,派件时效怎么分析

快递发货后&#xff0c;该如何快速查询到物流信息、比如怎么分析派件时效呢&#xff1f;今天小编给大家分享一个新的技巧&#xff0c;它支持多家快递&#xff0c;一次能查询多个单号物流&#xff0c;还能对查询到的物流进行分析、导出以及筛选&#xff0c;下面一起来试试吧。 …

3000万人气的腾格尔,会和金鸡奖提名电影《巴林塔娜》合作吗

刚刚结束的2022年11月19日&#xff0c;对于“草原歌神”腾格尔来说&#xff0c;注定是要被载入史册的一天。2022年11月19日&#xff0c;是卡特尔世界杯开幕式的前一夜&#xff0c;腾格尔老师也通过某音平台&#xff0c;开启了自己的线上演唱会。 说起明星们的演唱会&#xff0c…

redis 登录案例

下图就是登录controller Controller public class LoginController {RequestMapping("/login")public String Login(String username, String password, HttpServletResponse response){System.out.println(username);System.out.println(password);//判断账号密码 …

微信小程序 | IM交友聊天功能大汇总

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;小程序开发成神之路 --【这是一个为想要入门和进阶小程序开发专门开启的精品专栏&#xff01;从个人到商业的全套开发教程&#xff0c;实打实的干货分享&#xff0c;确定不来看看&#xff1f; …

关系数据库系统中的 NULL 值及其用途

在数据库中&#xff0c;NULL值具有非常特殊的含义。因此&#xff0c;重要的是要理解NULL值不同于零值或包含空格的字段。在今天的博客中&#xff0c;我们将探讨 NULL 值的含义以及如何在 Navicat Premium 中使用NULL。 什么是NULL&#xff1f; 应该注意的是&#xff0c;NULL值…

Linux上部署Kubectl(k8s)

Linux上部署Kubectl(k8s) 1.k8s简介 1.1 Kubernetes 概念 在 k8s 上进行部署前&#xff0c;首先需要了解一个基本概念 Deployment Deployment 译名为 部署。在k8s中&#xff0c;通过发布 Deployment&#xff0c;可以创建应用程序 (docker image) 的实例 (docker container)…

跑步需要哪些运动装备?跑步爱好者者的装备推荐

一开始我认为跑步是不需要装备的&#xff0c;毕竟是基础运动&#xff0c;但问了一下身边的运动大神才明白在长期的跑步锻炼&#xff0c;特别是长跑的过程中好的装备不但可以保护你免受伤害&#xff0c;还能帮助你更好的掌握运动状态&#xff0c;进行合理的锻炼下面我就给大家列…

[附源码]java毕业设计网上书店的设计

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

vite+vue-router4.x配置动态路由

踩过的坑&#xff1a; import直接导入组件; router.addRoute 并不能一次性给你导入&#xff08;即不是vue-router3.x以下的addRoutes&#xff09;&#xff1b; addRoute后页面空白&#xff1b; 直接上才艺&#xff01; 我的设计思路是登录后获取token&#xff0c;并存入cookie…

bizlog通用操作日志组件(代码分析篇)

引言 在上篇博客中介绍了通用操作日志组件的使用方法&#xff0c;本篇博客将从源码出发&#xff0c;学习一下该组件是如何实现的。 代码结构 该组件主要是通过AOP拦截器实现的&#xff0c;整体上可分为四个模块&#xff1a;AOP模块、日志解析模块、日志保存模块、Starter模块…

企业小程序商城的推广方式有哪些_分享小程序商城的作用

其实搭建小程序商城比较容易&#xff0c;难的是后期的运营。要想办法进行引流&#xff0c;用户运营伙伴就给大家介绍一些引流推广的方法。 1、利用微信好友、微信群和朋友圈 可以让用户分享小程序给微信好友或微信群&#xff0c;这是吸引新用户的最快方法。除此之外&#xff0…

Kettle入门到实战

简介 Kettle是一个方便ETL(数据的抽取&#xff0c;装换&#xff0c;装载)开源框架。 官网 kettle下载、kettle源码下载 – Kettle中文网 百度网盘下载 链接&#xff1a;https://pan.baidu.com/s/1C-izMX_3KMkRb5hhdj66xg 提取码&#xff1a;yyds --来自百度网盘超级会员…

go radix tree

Radix Tree Search Insert Insert ‘water’ at the root Insert ‘slower’ while keeping ‘slow’ Insert ‘test’ which is a prefix of ‘tester’ Insert ‘team’ while splitting ‘test’ and creating a new edge label ‘st’ Insert ‘toast’ while splitti…

java 多线程()—— 线程同步=队列+锁

一、线程同步 队列 锁 同步就是多个线程同时访问一个资源。 那么如何实现&#xff1f; 队列锁。 想要访问同一资源的线程排成一个队列&#xff0c;按照排队的顺序访问。访问的时候加上一个锁&#xff08;参考卫生巾排队锁门&#xff09;&#xff0c;访问完释放锁。 二、 不…

gitblit 搭建本地 git 仓库

目录 一、简介 二、准备工作 1.安装Java 2.下载gitblit 3.创建资料目录 三、修改配置 1.git.repositoriesFolder 2.server.httpPort 3.server.httpBindInterface 4.installService.cmd 四、gitblit图标显示异常 结束 一、简介 Gitblit是一个用于管理&#xff0c;查…

数据结构与算法这么重要还不会?字节内部笔记来帮你轻松拿下!

对任何专业技术人员来说&#xff0c;理解数据结构都非常重要。作为软件开发者&#xff0c;我们要能够用编程语言和数据结构来解决问题。编程语言和数据结构是这些问题解决方案中不可或缺的一部分。如果选择了不恰当的数据结构&#xff0c;可能会影响所写程序的性能。因此&#…

VKL076-19*4点 超低功耗抗干扰LCD液晶段码显示屏驱动控制电路(IC/芯片),超低工作电流约7.5微安,多用于仪器仪表类,可提供FAE技术支持

产品品牌&#xff1a;永嘉微电/VINKA 产品型号&#xff1a;VKL076 封装形式&#xff1a;SSOP28 概述&#xff1a; VKL076 SSOP28是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大76点&#xff08;19SEGx4COM&#xff09;的 LCD屏。单片机可通过I2C接口配置显示参数和…

【Hack The Box】linux练习-- SwagShop

HTB 学习笔记 【Hack The Box】linux练习-- SwagShop &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#x1…