Go语言进阶
个人笔记,大量摘自Go语言高级编程、Go|Dave Cheney等
更新
go get -u all
- 在非go目录运行
go install golang.org/x/tools/gopls@latest
- 更新go tools:
在go目录运行go get -u golang.org/x/tools/...
,会更新bin目录下的应用;
运行go install golang.org/x/tools/...@latest
- language server/linter:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- 生成调用关系图:
go install github.com/ofabry/go-callvis@latest
数组
var f = [...]int{}
定义一个长度为0的数组
长度为0的数组在内存中并不占用空间。空数组虽然很少直接使用,但是可以用于强调某种特有类型的操作时避免分配额外的内存空间,比如用于管道的同步操作:
c1 := make(chan [0]int)go func() {fmt.Println("c1")c1 <- [0]int{}}()<-c1
在这里,我们并不关心管道中传输数据的真实类型,其中管道接收和发送操作只是用于消息的同步。对于这种场景,我们用空数组来作为管道类型可以减少管道元素赋值时的开销。当然一般更倾向于用无类型的匿名结构体代替:
c2 := make(chan struct{})go func() {fmt.Println("c2")c2 <- struct{}{} // struct{}部分是类型, {}表示对应的结构体值}()<-c2
- 我们可以用fmt.Printf函数提供的%T或%#v谓词语法来打印数组的类型和详细信息:
fmt.Printf("b: %T\n", b) // b: [3]intfmt.Printf("b: %#v\n", b) // b: [3]int{1, 2, 3}
切片
a = a[N:] // 删除开头N个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素
a = a[:copy(a, a[N:])] // 删除开头N个元素
a = append(a[:i], a[i+N:]...) // 删除中间N个元素
a = a[:i+copy(a[i:], a[i+N:])] // 删除中间N个元素
结构
type structName struct {memberName string `fieldTag`
type Vertex struct {X, Y int
}
var (v1 = Vertex{1, 2} // has type Vertexv2 = Vertex{X: 1} // Y:0 is implicitv3 = Vertex{} // X:0 and Y:0
- 空结构: struct{} occupies no space, yet it can have member functions. So you can use it as value types of a map to substitute a boolean map for efficiency.
- 分配内存:
new(结构名)
或&结构名{}
函数
- 可变数量的参数
func f(a ...interface{}) {
var a = []interface{}{1, "a"}
f(a...)
解包调用,相当于f(1, "a")
- 通过叫方法表达式的特性可以将方法还原为普通类型的函数:
var CloseFile = (*File).Close
CloseFile(f)
结合闭包特性
f, _ := OpenFile("foo.dat")
var Close = func Close() error {return (*File).Close(f)
}
Close()
用方法值特性可以简化实现:
f, _ := OpenFile("foo.dat")
var Close = f.Close
Close()
- 通过在结构体内置匿名的成员来实现继承
type Point struct{ X, Y float64 }
type ColoredPoint struct {Point
直接使用匿名成员的成员:
var cp ColoredPoint
cp.X = 1
接口
- 有时候对象和接口之间太灵活了,导致我们需要人为地限制这种无意之间的适配。常见的做法是定义一个仅此接口需要的特殊方法。这个方法不对应实际有意义的实现。
- 再严格一点的做法是给接口定义一个私有方法。只有满足了这个私有方法的对象才可能满足这个接口,而私有方法的名字是包含包的绝对路径名的,因此只能在包内部实现这个私有方法才能满足这个接口。不过这种通过私有方法禁止外部对象实现接口的做法也是有代价的:首先是这个接口只能包内部使用,外部包正常情况下是无法直接创建满足该接口对象的;其次,这种防护措施也不是绝对的,恶意的用户依然可以绕过这种保护机制。
using io.Reader
- prefer
sc := bufio.NewScanner(r)
sc.Scan()
sc.Err()
to
_, err = bufio.NewReader(r).ReadString('\n')
because err == io.EOF when it reaches the end of file, making it more difficult to tell it from errors
modules
- go mod init 本模块名如gitee.com/bon-ami/eztools/v4
- use local modules
go mod edit -replace example.com/a@v1.0.0=./a
or manually in mod file
replace url.com/of/the/module => /direct/path/to/files
- update depended module, specifying a newer version
go get gitee.com/bon-ami/eztools@v1.1.3
- print path of main module
go list -m
. usego list -m example.com/hello@v0.1.0
to confirm the latest version is available - download modules
go mod download
- change go.mod
# Remove a replace directive.
$ go mod edit -dropreplace example.com/a@v1.0.0# Set the go version, add a requirement, and print the file
# instead of writing it to disk.
$ go mod edit -go=1.14 -require=example.com/m@v1.0.0 -print# Format the go.mod file.
$ go mod edit -fmt# Format and print a different .mod file.
$ go mod edit -print tools.mod# Print a JSON representation of the go.mod file.
$ go mod edit -json
- add/remove (un-)necessary modules
go mod tidy [-v]
- show go version
go version -m
- clean cache
go clean -modcache
- show module dependency in detail
go mod graph
- 离线使用:将在线下载好的${GOPATH}/go\pkg\mod拷贝到目标设备(包括其中
错误与异常
- syscall.Errno对应C语言中errno类型的错误
log.Fatal(err.(syscall.Errno))
err := recover()
将内部异常转为错误处理,比如在defer时使用;必须在defer函数中直接调用recover——如果defer中调用的是recover函数的包装函数的话,异常的捕获工作将失败;如果defer语句直接调用recover函数,依然不能正常捕获异常——必须和有异常的栈帧只隔一个栈帧。
defer func() { //分别处理各种异常,但是不符合异常的设计思想if r := recover(); r != nil {switch x := r.(type) {case string:err = errors.New(x)case runtime.Error: // 这是运行时错误类型异常case error: // 普通错误类型异常default: // 其他类型异常}}}()
fmt.Errorf(..., error)
将错误通过printf样格式化(%v)后重新生成错误var p *MyError = nil
将p以error类型返回时,返回的不是nil,而是一个正常的错误,错误的值是一个MyError类型的空指针:当接口对应的原始值为空的时候,接口对应的原始类型并不一定为空。
tests
- Replace user interaction with file content. Use
fmt.Fscanf
,fmt.Fscan
andioutil.TempFile
,io.WriteString
,in.Seek
. - failures of sub tests do not block main tests
t.Run(name, func(t *testing.T) {...})
go test -run=.*/name -v
to run subtest name.go test -run TestName
to run TestName.-args
后面参数可传到代码中:在init()
中flag.Int()
等,在测试代码执行时
if !flag.Parsed() {flag.Parse()}
go test -coverprofile=c.out
to see branch coverage of testsgo tool cover -func=c.out
to see function coverage of tests- github.com/pkg/expect 一般用不着
func TestOpenFile(t *testing.T) {f, err := os.Open("notfound")expect.Nil(err) //t.Fatal if err is not nil
部分具体实现:
func getT() *testing.T {var buf [8192]byten := runtime.Stack(buf[:], false)sc := bufio.NewScanner(bytes.NewReader(buf[:n]))for sc.Scan() {var p uintptrn, _ := fmt.Sscanf(sc.Text(), "testing.tRunner(%v", &p)if n != 1 {continue}return (*testing.T)(unsafe.Pointer(p))}return nil
}
- Benchmark
run all tests before all benchmarks
go test -bench=.
run *BenchmarksAdd* with no tests
go test -bench=BenchmarkAdd -run=XXXorNONEtoMakeItSimple -v
信号
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
//停等,截获^C之后继续
并发与同步
- sync.WaitGroup实例的
Add(数目)
后,Done()
释放一个,Wait()
等待指定数目释放完成 - sync.Mutex实例的
Lock()
、Unlock()
- 原子操作:
atomic.AddUint64(*uint64, uint64)
计算、atomic.LoadUint32(*uint32)
获取、atomic.StoreUint32(*uint32, uint32)
存储 - singleton:
once.Do(func() {由原子操作保证仅执行一次
})
- trylock. 可用channel+select模拟,但是容易导致活锁,所以不建议使用
// try lock
type Lock struct {c chan struct{}
}// NewLock generate a try lock
func NewLock() Lock {var l Lockl.c = make(chan struct{}, 1)l.c <- struct{}{}return l
}// Lock try lock, return lock result
func (l Lock) Lock() bool {lockResult := falseselect {case <-l.c:lockResult = truedefault:}return lockResult
}// Unlock , Unlock the try lock
func (l Lock) Unlock() {l.c <- struct{}{}
}
- atomic.Value原子对象提供了
Load
和Store
两个原子方法,分别用于加载和保存数据 - 同一个Goroutine线程内部,顺序一致性内存模型是得到保证的。但是不同的Goroutine之间,并不满足顺序一致性内存模型,需要通过明确定义的同步事件来作为同步的参考。
- 函数启动顺序:
- 函数参数中指定通道为:输出用
out chan<- 类型
;输入用in <-chan 类型
。用for v := range in
能无限等待、循环消费所有in通道数据。 - 无缓存的Channel上总会先完成接收再完成发送。带缓冲的Channel在缓冲满了时也是这样
- 最简结构用于流量控制
var tokenBucket = make(chan struct{}, capacity)tokenBucket <- struct{}{}:
- 若在关闭Channel后继续从中接收数据,接收者就会收到该Channel返回的零值。因此
close(管道)
可代替向管道发送完成信号:所有从关闭管道接收的操作均会收到一个零值和一个可选的失败标志。读取,直到管道关闭:for v := range ch
- 无限循环:
select{}、for{}、<-make(chan struct{})
空管道读、写永远阻塞 - 生产者消费者模型:消息发送到一个队列;
发布订阅(publish-and-subscribe)模型,即pub/sub:消息发布给一个主题
// Package pubsub implements a simple multi-topic pub-sub library.
package pubsubimport ("sync""time"
)type (subscriber chan interface{} // 订阅者为一个管道topicFunc func(v interface{}) bool // 主题为一个过滤器
)// 发布者对象
type Publisher struct {m sync.RWMutex // 读写锁buffer int // 订阅队列的缓存大小timeout time.Duration // 发布超时时间subscribers map[subscriber]topicFunc // 订阅者信息
}// 构建一个发布者对象, 可以设置发布超时时间和缓存队列的长度
func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher {return &Publisher{buffer: buffer,timeout: publishTimeout,subscribers: make(map[subscriber]topicFunc),}
}// 添加一个新的订阅者,订阅全部主题
func (p *Publisher) Subscribe() chan interface{} {return p.SubscribeTopic(nil)
}// 添加一个新的订阅者,订阅过滤器筛选后的主题
func (p *Publisher) SubscribeTopic(topic topicFunc) chan interface{} {ch := make(chan interface{}, p.buffer)p.m.Lock()p.subscribers[ch] = topicp.m.Unlock()return ch
}// 退出订阅
func (p *Publisher) Evict(sub chan interface{}) {p.m.Lock()defer p.m.Unlock()delete(p.subscribers, sub)close(sub)
}// 发布一个主题
func (p *Publisher) Publish(v interface{}) {p.m.RLock()defer p.m.RUnlock()var wg sync.WaitGroupfor sub, topic := range p.subscribers {wg.Add(1)go p.sendTopic(sub, topic, v, &wg)}wg.Wait()
}// 关闭发布者对象,同时关闭所有的订阅者管道。
func (p *Publisher) Close() {p.m.Lock()defer p.m.Unlock()for sub := range p.subscribers {delete(p.subscribers, sub)close(sub)}
}// 发送主题,可以容忍一定的超时
func (p *Publisher) sendTopic(sub subscriber, topic topicFunc, v interface{}, wg *sync.WaitGroup,
) {defer wg.Done()if topic != nil && !topic(v) {return}select {case sub <- v:case <-time.After(p.timeout):}
}
为select
加延时:case <-time.After(时长):
。
select
中条件检查channel读入值时不会阻塞case <-chan
只有其它条件不满足时,才会直到default:
匿名routine:go func() {}()
import "path/to/pubsub"func main() {p := pubsub.NewPublisher(100*time.Millisecond, 10)defer p.Close()all := p.Subscribe()golang := p.SubscribeTopic(func(v interface{}) bool {if s, ok := v.(string); ok {return strings.Contains(s, "golang")}return false})p.Publish("hello, world!")p.Publish("hello, golang!")go func() {for msg := range all {fmt.Println("all:", msg)}} ()go func() {for msg := range golang {fmt.Println("golang:", msg)}} ()// 运行一定时间后退出time.Sleep(3 * time.Second)
}
- 控制并发数
var limit = make(chan int, 3)
func main() {for _, w := range work {go func() {limit <- 1w()<-limit}()}select{}
}
- 用context实现素数筛,保证各goroutine收到退出的消息
// 返回生成自然数序列的管道: 2, 3, 4, ...
func GenerateNatural(ctx context.Context) chan int {ch := make(chan int)go func() {for i := 2; ; i++ {select {case <- ctx.Done():return nilcase ch <- i:}}}()return ch
}
// 管道过滤器: 删除能被素数整除的数
func PrimeFilter(ctx context.Context, in <-chan int, prime int) chan int {out := make(chan int)go func() {for {if i := <-in; i%prime != 0 {select {case <- ctx.Done():return nilcase out <- i:}}}}()return out
}
func main() {// 通过 Context 控制后台Goroutine状态ctx, cancel := context.WithCancel(context.Background())ch := GenerateNatural() // 自然数序列: 2, 3, 4, ...for i := 0; i < 100; i++ {prime := <-ch // 在每次循环迭代开始的时候,管道中的第一个数必定是素数fmt.Printf("%v: %v\n", i+1, prime)ch = PrimeFilter(ch, prime) // 基于管道中剩余的数列,并以当前取出的素数为筛子过滤后面的素数。不同的素数筛子对应的管道串联在一起}cancel()
}
CGo
- 以注释方式添加
//#include <stdlib.h>
/* void test() {} */
- .c和.go源文件一起编译
- 导入C包
import "C"
- C.CString转换字符串
- C.puts屏幕打印
- 通过桥接,用Go实现C声明的函数,再导入Go
//void SayHello(_GoString_ s);
import "C"
import "fmt"
func main() {C.SayHello("Hello, World\n")
}
//export SayHello
func SayHello(s string) {fmt.Print(s)
}
Remote Procedure Call
- RPC规则:方法只能有两个可序列化的参数,其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的方法。
服务器端:
type HelloService struct {}
func (p *HelloService) Hello(request string, reply *string) error {*reply = "hello:" + requestreturn nil
}
func main() {//将对象类型中所有满足RPC规则的对象方法注册为RPC函数,所有注册的方法会放在HelloService服务空间之下rpc.RegisterName("HelloService", new(HelloService))listener, err := net.Listen("tcp", ":1234")if err != nil {log.Fatal("ListenTCP error:", err)}conn, err := listener.Accept()if err != nil {log.Fatal("Accept error:", err)}rpc.ServeConn(conn)
}
客户端:
func main() {client, err := rpc.Dial("tcp", "localhost:1234")if err != nil {log.Fatal("dialing:", err)}var reply stringerr = client.Call("HelloService.Hello", "hello", &reply)if err != nil {log.Fatal(err)}fmt.Println(reply)
}
- 改进的服务器端:明确服务的名字和接口
const HelloServiceName = "path/to/pkg.HelloService"
type HelloServiceInterface = interface {Hello(request string, reply *string) error
}
func RegisterHelloService(svc HelloServiceInterface) error {return rpc.RegisterName(HelloServiceName, svc)
}
type HelloService struct {}
func (p *HelloService) Hello(request string, reply *string) error {*reply = "hello:" + requestreturn nil
}
func main() {RegisterHelloService(new(HelloService))listener, err := net.Listen("tcp", ":1234")if err != nil {log.Fatal("ListenTCP error:", err)}for {conn, err := listener.Accept()if err != nil {log.Fatal("Accept error:", err)}go rpc.ServeConn(conn)}
}
客户端
type HelloServiceClient struct {*rpc.Client
}
var _ HelloServiceInterface = (*HelloServiceClient)(nil)
func DialHelloService(network, address string) (*HelloServiceClient, error) {c, err := rpc.Dial(network, address)if err != nil {return nil, err}return &HelloServiceClient{Client: c}, nil
}
func (p *HelloServiceClient) Hello(request string, reply *string) error {return p.Client.Call(HelloServiceName+".Hello", request, reply)
}
func main() {client, err := DialHelloService("tcp", "localhost:1234")if err != nil {log.Fatal("dialing:", err)}var reply stringerr = client.Hello("hello", &reply)if err != nil {log.Fatal(err)}
}
- 跨语言的RPC:标准库的RPC默认采用Go语言特有的gob编码,因此从其它语言调用Go语言实现的RPC服务将比较困难。
用rpc.ServeCodec(jsonrpc.NewServerCodec(conn)
代替rpc.ServeConn(conn)
;用rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
代替rpc.Client
- HTTP实现RPC:
func main() {rpc.RegisterName("HelloService", new(HelloService))http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r *http.Request) {var conn io.ReadWriteCloser = struct {io.Writerio.ReadCloser}{ReadCloser: r.Body,Writer: w,}rpc.ServeRequest(jsonrpc.NewServerCodec(conn))})http.ListenAndServe(":1234", nil)
}
Protobuf & gRPC
- 下载protoc工具 后安装针对Go语言的代码生成插件:
go get github.com/golang/protobuf/protoc-gen-go
通过以下命令生成相应的Go代码:protoc --go_out=. hello.proto
其中go_out参数告知protoc编译器去加载对应的protoc-gen-go工具,然后通过该工具生成代码,生成代码放到当前目录。最后是一系列要处理的protobuf文件的列表。
gRPC:protoc --go_out=plugins=grpc:. hello.proto
- hello.proto示例
syntax = "proto3";package main;message String {string value = 1;
}service HelloService {rpc Hello (String) returns (String);
}
REST API
web
- 开源界有这么几种框架,第一种是对httpRouter进行简单的封装,然后提供定制的中间件和一些简单的小工具集成比如gin,主打轻量,易学,高性能。第二种是借鉴其它语言的编程风格的一些MVC类框架,例如beego,方便从其它语言迁移过来的程序员快速上手,快速开发。还有一些框架功能更为强大,除了数据库schema设计,大部分代码直接生成,例如goa。A famous router is Gorilla mux
- net/http
func echo(wr http.ResponseWriter, r *http.Request) {msg, err := ioutil.ReadAll(r.Body)wr.Write(msg)
}http.HandleFunc("/", echo)
http.ListenAndServe(":80", nil)
用context.Cancel
向要求处理线程结束
- http的mux可完成简单的路由
- RESTful: HEAD PATCH CONNECT OPTIONS TRACE
常见的请求路径:- 查找GET /repos/:owner/:repo/comments/:id/reactions
- 增加POST /projects/:project_id/columns
- 修改PUT /user/starred/:owner/:repo
- 删除DELETE /user/starred/:owner/:repo
- httprouter: 目前开源界最为流行(star数最多)的Web框架gin使用的就是其变种
r := httprouter.New()
r.NotFound = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("customized 404"))
})
压缩字典树(Radix Tree):以路由中相同一段作为节点的字典树(Trie Tree)
r.PUT("路由", 函数)
节点类型:
- static/default // 非根节点的普通字符串节点
- root // 根节点
- param // 参数节点,例如 :id
- catchAll // 通配符节点,只能在路由最后部分,例如 *anyway
- 使用中间件剥离非业务逻辑
a separate repository for middle wares of gin
Validator
- https://github.com/go-playground/validator: 使用参见
遍历结构
- 结构成员的标签:在成员
- 反射 reflect
vt := reflect.TypeOf()
- 解析单一成员的标签
vt.Field(i).Tag
vv := reflect.ValueOf()
- 成员数
vv.NumField()
- 单一成员
vv.Field(i)
- 分析其类型
vv.Field(i).Kind()
reflect.Int
reflect.String
reflect.Struct
- 取其为Interface{}
vv.Field(i).Interface()
vv.Field(i).Int()
vv.Field(i).String()
- 分析其类型
Web项目分层
- MVC=Module负责业务 View展示 Controller分发
- CLD=Controller+Logic业务逻辑 DataAccessObject存储
- 应用协议有(SOAP、REST、Thrift对比):
- SOAP 有状态,易鉴权
- REST 简单,无状态
- thrift 二进制,高效
- http
- gRPC
源文解析
AST simple explanation
internal packages
only code under /a/b or its subdirectories can include /a/b/internal/d/e
跨平台编码
- 查看当前平台编译某目录会编译哪些文件
go list -f '{{.GoFiles}}' 代码目录
- 方式一 为代码文件名加后缀而成为
_$GOOS.go
、_$GOARCH.go
或_$GOOS_$GOARCH.go
- 方式二 Build Tags在代码文件中尽量靠前,它控制本文件是否参与编译:
// +build linux darwin
// +build 386,!amd64
只在linux, darwin, 386,且非64位上参与编译。
- a build tag is evaluated as the OR of space-separated options
- each option evaluates as the AND of its comma-separated terms
- each term is an alphanumeric word or, preceded by !, its negation
在声明与包声明之间需要空行,以免被认为是包的说明
go command parameters
-
The commands are:
bug start a bug reportbuild compile packages and dependenciesclean remove object files and cached files-modcache clean module cachedoc show documentation for package or symbolenv print Go environment informationfix update packages to use new APIsfmt gofmt (reformat) package sourcesgenerate generate Go files by processing sourceget download and install packages and dependenciesinstall compile and install packages and dependencieslist list packages (or modules)-m list modules. "-m all" list with dependants.mod module maintenancerun compile and run Go programtest test packages.-v makes t.Log() print immediately instead of on the end of the test-bench=. runs benchmarktool run specified go toolversion print Go version-m about a modulevet report likely mistakes in packages
-
Additional help topics:
buildmode build modesc calling between Go and Ccache build and test cachingenvironment environment variablesfiletype file typesgo.mod the go.mod filegopath GOPATH environment variablegopath-get legacy GOPATH go getgoproxy module proxy protocolimportpath import path syntaxmodules modules, module versions, and moremodule-get module-aware go getmodule-auth module authentication using go.summodule-private module configuration for non-public modulespackages package lists and patternstestflag testing flagstestfunc testing functions
灰度发布 Canary
- 分批次部署:从一个开始以2的级数增加发布用户数
- 按业务规则:根据用户信息生成一个简单的哈希值,然后求模——比如对1000,比2小则为3‰
inlining
- inlining budget. 编译选项-gcflags=-m=2可显示哪些函数会被inline
- hariness. recover, break, select, go, for, range都会由于hairy造成不被inline
相关文章:

Go语言进阶
个人笔记,大量摘自Go语言高级编程、Go|Dave Cheney等 更新 go get -u all 在非go目录运行go install golang.org/x/tools/goplslatest更新go tools:在go目录运行go get -u golang.org/x/tools/...,会更新bin目录下的应用; 运行…...
Java的枚举
枚举 对应英文(enumeration, 简写enum) 枚举是一组常量的集合,属于一种特殊的类,里面只包含一组有限的特定的对象。 自定义类实现枚举 1.不需要提供setXxx方法,因为枚举对象值通常为只读. 2.对枚举对象/属性使用 final static共同修饰…...

Pytest测试框架3
目录: pytest结合数据驱动-yamlpytest结合数据驱动-excelpytest结合数据驱动-csvpytest结合数据驱动-jsonpytest测试用例生命周期管理(一)pytest测试用例生命周期管理(二)pytest测试用例生命周期管理(三&a…...

【数学建模】-- Matlab中图的最短路径
前言: 图的基本概念: 若想简单绘制图可以利用此网站: 左上角Undirected/Directed是无向图/有向图 左边 0-index ,1-index为0下标,1下标。 Node Count为节点个数 Graph Data:最初尾节点的名称ÿ…...
中国月入过万的人多不多
Q:中国月入过万的人多不多 单从这个问题来看,这是个费米问题啊: 估算中国月入过万的有多少人? 要解决费米问题,其实也很好办,就是逻辑拆解,这篇文章也分为3个部分,先从公开数据中估…...

苹果电脑图像元数据编辑器:MetaImage for Mac
MetaImage for Mac是一款功能强大的照片元数据编辑器,它可以帮助用户编辑并管理照片的元数据信息,包括基本信息和扩展信息。用户可以根据需要进行批量处理,方便快捷地管理大量照片。 MetaImage for Mac还提供了多种导入和导出格式࿰…...
BeanUtils.copyProperties() 详解
BeanUtils.copyProperties会进行类型转换; BeanUtils.copyProperties方法简单来说就是将两个字段相同的对象进行属性值的复制。如果 两个对象之间存在名称不相同的属性,则 BeanUtils 不对这些属性进行处理,需要程序手动处理。 这两个类在不同…...

基于CentOS 7构建LVS-DR集群
DIPVIPRIPClient192.169.41.139 LVS 192.168.41.134192.169.41.10RS1192.168.41.135RS2192.168.41.138 要求: node4为客户端,node2为LVS,node3和node4为RS。 1.配置DNS解析(我这里使用本地解析) 192.168.41.134 www.y…...

openEuler-OECA考试报名火热开启,尊享半价优惠 作者:HopeInfra 发布时间:2023-08-10
近日,润和软件人才评定报名系统已成功上线运行,现openEuler-OECA人才评定考试报名优惠活动火热开启,欢迎大家报名咨询! 关于openEuler人才评定 随着openEuler及其发行版本在各个行业使用量逐年增多,相关人才的评定诉求…...

侯捷 C++面向对象编程笔记——10 继承与虚函数
10 继承与虚函数 10.1 Inheritance 继承 语法::public base_class_name public 只是一种继承的方式,还有protect,private 子类会拥有自己的以及父类的数据 10.1.1 继承下的构造和析构 与复合下的构造和析构相似 构造是由内而外 Container …...
mysql日期函数(查询最近n(天/月/年)、计算日期之间的天数等)
mysql日期函数 目录 mysql查询最近一个月数据返回当前日期和时间将字符串转变为日期日期 d 减去 n 天后的日期计时间差,返回 datetime_expr2 − datetime_expr1 的时间差算查询当天数据 ADDDATE(d,n)计算起始日期 d 加上 n 天的日期 SELECT ADDDATE("2017-06…...

通过anvt X6和vue3实现图编辑
通过anvt X6 X6地址:https://x6.antv.antgroup.com/tutorial/about; 由于节点比较复杂,使用vue实现的节点; x6提供了一个独立的包 antv/x6-vue-shape 来使用 Vue 组件渲染节点。 VUE3的案例: <template><div…...
win2012 IIS8.5 安装PHP教程,一些版本不能用
因为一直用win2003IIS6.0PHP的环境,所以搭建PHP自认为非常熟悉了,但是最近在搭建win2012IIS8.5PHP的环境时,我遇到了一些问题,经过4个小时的折腾,终于搞定了,本文记录一些经验,可能不少朋友也会…...
sqlalchemy执行原生sql
# 有的复杂sql 用orm写不出来---》用原生sql查询 # 原生sql查询,查出的结果是对象 # 原生sql查询,查询结果列表套元组 准备工作 from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engineengine create_engine(&…...

Python-OpenCV中的图像处理-图像平滑
Python-OpenCV中的图像处理-图像平滑 图像平滑平均滤波高斯模糊中值模糊双边滤波 图像平滑 使用低通滤波器可以达到图像模糊的目的。这对与去除噪音很有帮助。其实就是去除图像中的高频成分(比如:噪音,边界)。所以边界也会被模糊…...

Mongoose http server 例子
今天抽了点时间看了一下 mongoose的源码, github 地址,发现跟以前公司内部使用的不太一样,这里正好利用其 http server 例子来看一下。以前的 http message 结构体是这样的: /* HTTP message */ struct http_message {struct mg_…...
1、初识HTML
1、初识HTML 前端就是写一些基本的页面,HTML即超文本标记语言:Hyper Text Markup Language,超文本包括,文字、图片、音频、视频、动画等,HTML5,提供了一些新的元素和一些有趣的新特性,同时也建…...

线性代数(三) 线性方程组
前言 如何利用行列式,矩阵求解线性方程组。 线性方程组的相关概念 用矩阵方程表示 齐次线性方程组:Ax0;非齐次线性方程组:Axb. 可以理解 齐次线性方程组 是特殊的 非齐次线性方程组 如何判断线性方程组的解 其中R(A)表示矩阵A的…...

Apoll 多项式规划求解
一、纵向规划 void QuarticPolynomialCurve1d::ComputeCoefficients(const float x0, const float dx0, const float ddx0, const float dx1,const float ddx1, const float p) {if (p < 0.0) {std::cout << "p should be greater than 0 at line 140." &…...

ssm亚盛汽车配件销售业绩管理统源码和论文PPT
ssm亚盛汽车配件销售业绩管理统源码和论文PPT007 开发工具:idea 数据库mysql5.7(mysql5.7最佳) 数据库链接工具:navcat,小海豚等 开发技术:java ssm tomcat8.5 研究的意义 汽车配件销售类企业近年来得到长足发展,在市场份额不断扩大同时…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...