Golang 依赖注入库Wire应用案例

文章目录

  • 简介
  • Github
  • 指南
  • 安装
  • 案例
    • wire.NewSet
    • wire.Build
    • wire.Bind
    • wire.Struct
    • wire.Value
    • wire.InterfaceValue

简介

Go语言的依赖注入库Wire是由Google提供的一个代码生成工具,用于简化和自动化依赖注入过程。Wire主要通过生成代码来处理依赖关系,而不是在运行时动态地解决依赖,这使得它更高效且易于调试。

  • wire.NewSet: NewSet 函数用于创建一个新的依赖集合。你可以将需要被注入的类型和提供这些类型依赖的函数放入到这个集合中。

  • wire.Build: Build 函数用于生成依赖注入代码。你可以将之前创建的依赖集合传递给 Build 函数,然后它将生成相应的代码用于构建依赖。

  • wire.Bind: Bind 函数用于将一个接口类型与其实现类型进行绑定。这样在依赖注入时,当需要注入某个接口类型时,Wire会知道该使用哪个具体的实现类型。

  • wire.Struct: Struct 函数用于将结构体类型与其字段进行绑定。这样在依赖注入时,可以将结构体的字段通过依赖注入的方式进行初始化。

  • wire.Value: Value 函数用于声明一个特定的值作为依赖。在依赖注入时,这个值会被直接使用,而不需要再进行额外的初始化。

  • wire.InterfaceValue: InterfaceValue 函数用于声明一个接口类型的值作为依赖。在依赖注入时,这个值会被用作接口类型的实现。

  • Wire的应用场景:

    • 构建复杂依赖图:Wire特别适用于处理具有复杂依赖关系的应用程序,尤其是当依赖项数量庞大且层次深厚时。

    • 简化初始化逻辑:通过自动生成依赖注入代码,Wire简化了对象的初始化逻辑,使代码更加简洁和易于维护。

    • 提高代码可测试性:通过接口绑定和依赖注入,Wire可以帮助实现松耦合结构,从而提高代码的可测试性。

    • 提升性能:Wire在编译时解析和生成依赖注入代码,因此在运行时不需要额外的依赖解析步骤,这使得它比一些运行时依赖注入框架更高效。

Github

  • https://github.com/google/wire

指南

  • https://github.com/google/wire/blob/main/docs/guide.md

安装

go get github.com/google/wire/cmd/wire
# 安装
go install github.com/google/wire/cmd/wire@latest

案例

wire.NewSet

wire.NewSet 是 Wire 库中用于创建依赖集合的函数。在依赖注入的场景中,你可以使用 wire.NewSet 将多个提供者函数(即构造函数)或现有值组合到一起,形成一个提供依赖项的集合。这对于组织和管理依赖项非常有帮助。

  • 应用场景
    • 分组管理依赖项:你可以将相关的依赖项分组到一个集合中,方便在不同的构建上下文中复用这些依赖项。
    • 模块化设计:通过创建不同的依赖集合,可以更清晰地表达模块之间的依赖关系。
    • 测试:可以创建不同的依赖集合用于测试,以便轻松替换实际依赖项。

wire.Build

wire.Build 是 Wire 库中的核心函数,用于生成依赖注入代码。它通过构建依赖图,根据提供的依赖集合自动生成所需的初始化代码。

  • 应用场景
    • 复杂依赖关系管理:在大型应用程序中,管理复杂的依赖关系是很困难的,使用 wire.Build 可以自动处理这些依赖。
    • 模块化开发:在模块化开发中,每个模块可能有自己的依赖项,通过 wire.Build 可以轻松组合不同模块的依赖。
    • 测试和替换依赖:在测试中,使用 wire.Build 可以方便地替换实际依赖项以进行单元测试。

在这里插入图片描述

  1. 定义依赖项和构造函数:定义 Database, HTTPServer 和 App 结构体,以及它们的构造函数。
  2. 创建依赖集合:使用 wire.NewSet 将构造函数组合成集合 ProviderSet。
  3. 生成依赖注入代码:在 app/wire.go 中,使用 wire.Build 和 ProviderSet 生成依赖注入代码。
  4. 使用生成的代码:在 main.go 中,调用 app.InitApp 函数初始化应用程序。
cd demo
# 初始化
go mod init example.com/demo
# 下载依赖库
go mod tidy
  • app/app.go
package appimport ("github.com/google/wire""example.com/demo/db""example.com/demo/server"
)// App 是我们的应用程序,依赖于 HTTPServer
type App struct {Server *server.HTTPServer
}// NewApp 是 App 的构造函数
func NewApp(server *server.HTTPServer) *App {return &App{Server: server,}
}// ProviderSet 是应用程序模块的依赖集合
var ProviderSet = wire.NewSet(NewApp, db.ProviderSet, server.ProviderSet)
  • app/wire.go
// +build wireinjectpackage appimport ("github.com/google/wire"
)// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {wire.Build(ProviderSet)return &App{}
}
  • app/wire_gen.go(生成的代码)
// Code generated by Wire. DO NOT EDIT.//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage appimport ("example.com/demo/db""example.com/demo/server"
)// Injectors from wire.go:// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {database := db.NewDatabase()httpServer := server.NewHTTPServer(database)app := NewApp(httpServer)return app
}
  • db/db.go
package dbimport "github.com/google/wire"// Database 是一个简单的数据库连接模拟
type Database struct {DSN string
}// NewDatabase 是 Database 的构造函数
func NewDatabase() *Database {return &Database{DSN: "user:password@/dbname",}
}// ProviderSet 是数据库模块的依赖集合
var ProviderSet = wire.NewSet(NewDatabase)
  • server/server.go
package serverimport ("example.com/demo/db""github.com/google/wire"
)// HTTPServer 是一个简单的 HTTP 服务器
type HTTPServer struct {DB *db.Database
}// NewHTTPServer 是 HTTPServer 的构造函数
func NewHTTPServer(db *db.Database) *HTTPServer {return &HTTPServer{DB: db,}
}// ProviderSet 是服务器模块的依赖集合
var ProviderSet = wire.NewSet(NewHTTPServer)
  • main.go
package mainimport ("fmt""example.com/demo/app"
)func main() {// 调用 app 包中的 InitApp 函数初始化应用myApp := app.InitApp()fmt.Printf("App initialized with server: %+v\n", myApp.Server)
}
  • 生成wire_gen.go
cd demo && wire
# 或
cd demo/app && wire
cd demo
go run .

wire.Bind

wire.Bind 是 Wire 提供的一个功能,用于将接口类型与具体实现类型绑定。这在依赖注入的场景中特别有用,因为它允许你将接口注入到依赖树中,而不是具体实现,从而实现更灵活和可测试的代码结构。

  • 应用场景
    • 接口与实现的解耦:当你的代码依赖于接口而不是具体实现时,可以更容易地更换实现或者进行单元测试。
    • 依赖注入中的多态性:在构建依赖图时,可以选择不同的具体实现绑定到相同的接口上,以实现多态行为。

在这里插入图片描述

  1. 定义接口和实现:在 service 包中定义 Service 接口和 RealService 实现。
  2. 构造函数和 ProviderSet:定义 NewRealService 构造函数和 ProviderSet,并使用 wire.Bind 将 Service 接口绑定到 RealService 实现。
  3. 使用依赖注入:在 app 包中定义 App 结构体及其构造函数 NewApp,并在 ProviderSet 中包含 service.ProviderSet。
  4. 生成 Wire 代码:在 app/wire.go 中使用 wire.Build 和 ProviderSet 生成依赖注入代码。
  5. 初始化应用:在 main.go 中调用 app.InitApp 初始化应用,并调用服务的方法。
  • app/app.go
package appimport ("github.com/google/wire""example.com/demo/service"
)// App 是我们的应用程序,依赖于 Service
type App struct {Service service.Service
}// NewApp 是 App 的构造函数
func NewApp(service service.Service) *App {return &App{Service: service,}
}// ProviderSet 是应用程序模块的依赖集合
var ProviderSet = wire.NewSet(NewApp, service.ProviderSet)
  • app/wire.go
// +build wireinjectpackage appimport ("github.com/google/wire"
)// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {wire.Build(ProviderSet)return &App{}
}
  • app/wire_gen.go(生成的代码)
// Code generated by Wire. DO NOT EDIT.//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage appimport ("example.com/demo/service"
)// Injectors from wire.go:// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {realService := service.NewRealService()app := NewApp(realService)return app
}
  • service/service.go
package serviceimport ("github.com/google/wire"
)// Service 是一个接口,定义了服务的行为
type Service interface {Serve() string
}// RealService 是 Service 接口的具体实现
type RealService struct{}// Serve 是 RealService 的 Serve 方法实现
func (s *RealService) Serve() string {return "Real service serving"
}// NewRealService 是 RealService 的构造函数
func NewRealService() *RealService {return &RealService{}
}// ProviderSet 是服务模块的依赖集合
var ProviderSet = wire.NewSet(NewRealService,wire.Bind(new(Service), new(*RealService)),
)
  • main.go
package mainimport ("fmt""example.com/demo/app"
)func main() {// 调用 app 包中的 InitApp 函数初始化应用myApp := app.InitApp()fmt.Println(myApp.Service.Serve())
}

wire.Struct

wire.Struct 是 Wire 提供的一个功能,用于简化结构体的构造。当一个结构体有多个字段需要注入时,wire.Struct 可以自动生成构造函数,注入所有字段。它特别适用于需要依赖注入的复杂结构体。

  • 应用场景
    • 简化构造函数:当一个结构体有很多字段时,手动编写构造函数可能会很繁琐,使用 wire.Struct 可以自动生成构造函数。
    • 减少样板代码:在大型项目中,减少手动编写的构造函数代码,提高开发效率。
    • 保证依赖注入的正确性:通过自动生成构造函数,减少人为错误。

在这里插入图片描述

  1. 定义结构体:在 app 包中定义 App 结构体,它依赖于 HTTPServer 和 Database。
  2. 使用 wire.Struct:在 ProviderSet 中使用 wire.Struct(new(App), “*”),表示将自动生成 App 的构造函数并注入所有字段。
  3. 生成依赖注入代码:在 app/wire.go 中使用 wire.Build 和 ProviderSet 生成依赖注入代码。
  4. 初始化应用:在 main.go 中调用 app.InitApp 函数初始化应用。
  • app/app.go
package appimport ("github.com/google/wire""example.com/demo/db""example.com/demo/server"
)// App 是我们的应用程序,依赖于 HTTPServer 和 Database
type App struct {Server *server.HTTPServerDb     *db.Database
}// ProviderSet 是应用程序模块的依赖集合
var ProviderSet = wire.NewSet(wire.Struct(new(App), "*"), db.ProviderSet, server.ProviderSet)
  • app/wire.go
// +build wireinjectpackage appimport ("github.com/google/wire"
)// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {wire.Build(ProviderSet)return &App{}
}
  • app/wire_gen.go(生成的代码)
// Code generated by Wire. DO NOT EDIT.//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage appimport ("example.com/demo/db""example.com/demo/server"
)// Injectors from wire.go:// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {database := db.NewDatabase()httpServer := server.NewHTTPServer(database)app := &App{Server: httpServer,Db:     database,}return app
}
  • db/db.go
package dbimport "github.com/google/wire"// Database 是一个简单的数据库连接模拟
type Database struct {DSN string
}// NewDatabase 是 Database 的构造函数
func NewDatabase() *Database {return &Database{DSN: "user:password@/dbname",}
}// ProviderSet 是数据库模块的依赖集合
var ProviderSet = wire.NewSet(NewDatabase)
  • server/server.go
package serverimport ("example.com/demo/db""github.com/google/wire"
)// HTTPServer 是一个简单的 HTTP 服务器
type HTTPServer struct {DB *db.Database
}// NewHTTPServer 是 HTTPServer 的构造函数
func NewHTTPServer(db *db.Database) *HTTPServer {return &HTTPServer{DB: db,}
}// ProviderSet 是服务器模块的依赖集合
var ProviderSet = wire.NewSet(NewHTTPServer)
  • main.go
package mainimport ("fmt""example.com/demo/app"
)func main() {// 调用 app 包中的 InitApp 函数初始化应用myApp := app.InitApp()fmt.Printf("App initialized with server: %+v\n", myApp.Server)
}

wire.Value

wire.Value 是 Wire 提供的一个功能,用于注入一个特定的值。这在配置项或常量注入等场景中特别有用,能够为依赖注入过程提供静态的值。

  • 应用场景
    • 配置注入:将配置项(如数据库连接字符串、API 密钥等)注入到依赖树中。
    • 静态值注入:对于某些不会改变的常量值,使用 wire.Value 注入这些值。
    • 默认值注入:为某些依赖项提供默认值。

在这里插入图片描述

  1. 定义配置结构体:在 config 包中定义 Config 结构体和 NewConfig 构造函数。
  2. 使用 wire.Value:在 config.ProviderSet 中使用 wire.Value(Config{DSN: “user:password@/dbname”}) 注入静态配置值。
  3. 定义数据库结构体:在 db 包中定义 Database 结构体和 NewDatabase 构造函数。
  4. 构建依赖树:在 app 包中定义 App 结构体及其构造函数 NewApp,并在 ProviderSet 中包含 db.ProviderSet 和 config.ProviderSet。
  5. 生成依赖注入代码:在 app/wire.go 中使用 wire.Build 和 ProviderSet 生成依赖注入代码。
  6. 初始化应用:在 main.go 中调用 app.InitApp 函数初始化应用。
  • app/app.go
package appimport ("github.com/google/wire""example.com/demo/db"
)// App 是我们的应用程序,依赖于 Database
type App struct {Database *db.Database
}// NewApp 是 App 的构造函数
func NewApp(database *db.Database) *App {return &App{Database: database,}
}// ProviderSet 是应用程序模块的依赖集合
var ProviderSet = wire.NewSet(NewApp, db.ProviderSet)
  • app/wire.go
// +build wireinjectpackage appimport ("github.com/google/wire""example.com/demo/config"
)// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {wire.Build(ProviderSet, config.ProviderSet)return &App{}
}
  • app/wire_gen.go(生成的代码)
// Code generated by Wire. DO NOT EDIT.//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage appimport ("example.com/demo/config""example.com/demo/db"
)// Injectors from wire.go:// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {config := _wireConfigValuedatabase := db.NewDatabase(config)app := NewApp(database)return app
}var (_wireConfigValue = config.Config{DSN: "user:password@/dbname"}
)
  • config/config.go
package configimport "github.com/google/wire"// Config 是一个简单的配置结构体
type Config struct {DSN string
}// NewConfig 是 Config 的构造函数
func NewConfig(dsn string) *Config {return &Config{DSN: dsn,}
}// ProviderSet 是配置模块的依赖集合
var ProviderSet = wire.NewSet(wire.Value(Config{DSN: "user:password@/dbname"}),
)
  • db/db.go
package dbimport ("example.com/demo/config""github.com/google/wire"
)// Database 是一个简单的数据库连接模拟
type Database struct {DSN string
}// NewDatabase 是 Database 的构造函数
func NewDatabase(config config.Config) *Database {return &Database{DSN: config.DSN,}
}// ProviderSet 是数据库模块的依赖集合
var ProviderSet = wire.NewSet(NewDatabase)
  • main.go
package mainimport ("fmt""example.com/demo/app"
)func main() {// 调用 app 包中的 InitApp 函数初始化应用myApp := app.InitApp()fmt.Printf("App initialized with database DSN: %+v\n", myApp.Database.DSN)
}

wire.InterfaceValue

wire.InterfaceValue 是 Wire 提供的一个功能,用于将一个特定的实现绑定到一个接口。这在依赖注入中非常有用,特别是在你有多个实现并且希望在运行时或编译时决定使用哪个实现的情况下。

  • 应用场景
    • 接口实现的动态选择:当你的代码依赖于接口而不是具体实现时,可以使用 wire.InterfaceValue 动态选择不同的实现。
    • 配置驱动的实现选择:根据配置或环境变量选择不同的实现。
    • 测试替身的注入:在测试中,可以用 wire.InterfaceValue 注入模拟或替身实现。

在这里插入图片描述

  1. 定义接口和实现:在 service 包中定义 Service 接口和 RealService, MockService 实现。
  2. 配置选择实现:在 config 包中定义 SelectedService 函数,用于选择具体的服务实现。
  3. 使用 wire.InterfaceValue:在 app/wire.go 中使用 wire.InterfaceValue 将 config.SelectedService() 的返回值绑定到 Service 接口。
  4. 构建依赖树:在 app 包中定义 App 结构体及其构造函数 NewApp,并在 ProviderSet 中包含 service.ProviderSet。
  5. 生成依赖注入代码:在 app/wire.go 中使用 wire.Build 和 ProviderSet 生成依赖注入代码。
  6. 初始化应用:在 main.go 中调用 app.InitApp 函数初始化应用,并调用服务的方法。
  • app/app.go
package appimport ("github.com/google/wire""example.com/demo/service"
)// App 是我们的应用程序,依赖于 Service
type App struct {Service service.Service
}// NewApp 是 App 的构造函数
func NewApp(service service.Service) *App {return &App{Service: service,}
}// ProviderSet 是应用程序模块的依赖集合
var ProviderSet = wire.NewSet(NewApp, service.ProviderSet)
  • app/wire.go
// +build wireinjectpackage appimport ("github.com/google/wire""example.com/demo/config""example.com/demo/service"
)// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {wire.Build(ProviderSet,wire.InterfaceValue(new(service.Service), config.SelectedService()),)return &App{}
}
  • app/wire_gen.go(生成的代码)
// Code generated by Wire. DO NOT EDIT.//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage appimport ("example.com/demo/config"
)// Injectors from wire.go:// InitApp 使用 Wire 生成依赖注入代码
func InitApp() *App {service := _wireServiceValueapp := NewApp(service)return app
}var (_wireServiceValue = config.SelectedService()
)
  • config/config.go
package configimport "example.com/demo/service"// SelectedService 返回要使用的服务实现
func SelectedService() service.Service {// 根据需要选择实际的服务实现,这里可以是基于配置或环境变量的逻辑return &service.RealService{}
}
  • db/db.go
package dbimport ("example.com/demo/config""github.com/google/wire"
)// Database 是一个简单的数据库连接模拟
type Database struct {DSN string
}// NewDatabase 是 Database 的构造函数
func NewDatabase(config config.Config) *Database {return &Database{DSN: config.DSN,}
}// ProviderSet 是数据库模块的依赖集合
var ProviderSet = wire.NewSet(NewDatabase)
  • service/service.go
package serviceimport "github.com/google/wire"// Service 是一个接口,定义了服务的行为
type Service interface {Serve() string
}// RealService 是 Service 接口的一个具体实现
type RealService struct{}func (s *RealService) Serve() string {return "Real service serving"
}// MockService 是 Service 接口的另一个具体实现
type MockService struct{}func (s *MockService) Serve() string {return "Mock service serving"
}// ProviderSet 是服务模块的依赖集合
var ProviderSet = wire.NewSet()
  • main.go
package mainimport ("fmt""example.com/demo/app"
)func main() {// 调用 app 包中的 InitApp 函数初始化应用myApp := app.InitApp()fmt.Println(myApp.Service.Serve())
}

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

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

相关文章

上网行为管理产品有哪些?好用的四款上网行为管理产品

上网行为管理产品是现代企业网络安全架构中的重要组成部分,它们旨在帮助企业有效监控、管理和控制员工的网络使用行为,确保网络资源的合理利用,保障信息安全,提升工作效率。 以安企神为例,我们将详细介绍它的主要功能…

【内存管理之C语言数组】

1.栈空间上的C数组 糟糕的可用性,但是你将在遗留代码中见到它们 相同类型的对象的内存块 大小必须是常量表达式 第一个元素索引为0 2.指针和C数组 更奇怪的是:数组标识符退化为指向第一个元素的指针 3.访问数组 4.堆空间上的C数组 相同类型的对象的内…

SSM情侣购物系统-计算机毕业设计源码02387

目 录 摘要 1 绪论 1.1 开发背景与意义 1.2开发意义 1.3Vue.js 主要功能 1.3论文结构与章节安排 2 情侣购物系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分…

Qwen2的各模型性能、占用显存和推理速度比较(摘自官方文档)

Qwen2的各模型性能、占用显存和推理速度比较(摘自官方文档) 性能 推理速度(从大到小) 72B 57B-A14B 7B 1.5B 0.5B

59.WEB渗透测试-信息收集- 端口、目录扫描、源码泄露(7)

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于: 易锦网校会员专享课 上一个内容:58.WEB渗透测试-信息收集- 端口、目录扫描、源码泄露(6) 关于御剑…

【TB作品】STM32F102C8T6单片机,PWM发生器

硬件: STM32F102C8T6核心板,按键,0.96 OLED显示屏。 软件: 1、硬件启动触发单片机输出PWM,未触发之前PWM输出为低电平。 2、按键修改PWM的变化模式、变化时间长度、占空比上下限。 3、输出的PWM是固定的10kHZ的。 4、变…

【万方数据库爬虫简单开发(自用)】

万方数据库爬虫简单开发(自用)(一) 使用Python爬虫实现万方数据库论文的搜索并获取信息1.获取url2.输入关键词3.使用BeautifulSoup解析4.获取文章标题信息 使用Python爬虫实现万方数据库论文的搜索并获取信息 后续会逐步探索更新…

洗地机哪款好?洗地机十大名牌排行榜

随着科技的发展,各种家居清洁工具层出不穷,为我们的生活带来了诸多便利。在众多清洁工具中,洗地机的清洁效果更受大家喜爱,它能够完美解决了扫地机无法做到的干湿垃圾“一遍清洁”效果,而且几乎能解决日常生活中所有的…

笔记 | 软件工程06-1:软件设计-软件设计基础

1 软件设计概述 1.1 为什么要软件设计 1.2 何为软件设计 何为软件系统的解决方案? 软件设计关注与软件需求的实现问题软件设计是需求分析和软件实现间的桥梁 1.3 软件设计的质量要求 1.4 软件设计的过程 1.4.1 软件体系结构设计 1.4.2 用户界面设计 1.4.3 软件详细…

如何轻松利用人工智能深度学习,提升半导体制造过程中的良率预测?

背景 这个项目涉及半导体制造过程的监测领域。在半导体制造中,不断收集来自传感器或过程测量点的信号是常态。然而,并非所有这些信号在特定的监测系统中都同等重要。这些信号包括了有用的信息、无关的信息以及噪声。通常情况下,工程师获得的…

将Jar用三种方式生成Windows的安装程序

无论是WEB(spring boot)的JAR,还是JavaFX以及swing的Jar,要生成windows方式。 打包成Windows可执行文件(.exe),你可以使用以下三种方法: ### 方法1:使用Inno Setup 1. **构建JavaFX应用程序**: 使用M…

2779. 数组的最大美丽值

简单翻译一下题目意思: 对于每个 nums[i] 都可以被替换成 [nums[i]-k, nums[i]k] 区间中的任何数,区间左右是闭的。在每个数字可以替换的前提下,返回数组中最多的重复数字的数量。 第一想法是用一个哈希表,Key 是可以被替换的数…

Kotlin 语言基础学习

什么是Kotlin ? Kotiln翻译为中文是:靠他灵。它是由JetBrains 这家公司开发的,JetBrains 是一家编译器软件起家的,例如常用的WebStorm、IntelliJ IDEA等软件。 Kotlin官网 JetBrains 官网 Kotlin 语言目前的现状: 目前Android 已将Kotlin 作为官方开发语言。 Spring 框…

硬件SPI读写W25Q64

硬件SPI读写W25Q64 接线图(和软件SPI一样) 使用SPI1,SCK,接PA5;MISO,接PA6;MOSI,接PA7;NSS,可接PA4。 接线图对应:PA5接CLK引脚,PA6…

【数据结构】第十六弹---C语言实现希尔排序

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1、希尔排序( 缩小增量排序 ) 1.1、预排序实现 1.2、希尔排序代码实现 1.3、代码测试 1.4、时空复杂度分析 1.5、性能比较 总结 上一弹我们…

【产品应用】一体化步进伺服电机在吊装机器人中的应用

随着工业自动化和智能制造的发展,吊挂式智能巡检机器人逐渐成为许多工业场景中的重要角色。这类机器人不仅能够提升工作效率,减少人工干预,还能在复杂或危险环境中完成巡检任务。在这些机器人的设计与制造中,一体化步进伺服电机扮…

windows环境如何运行python/java后台服务器进程而不显示控制台窗口

1.通常我们在windows环境下使用Java或Python语言编写服务器程序,都希望他在后台运行,不要显示黑乎乎的控制台窗口: 2.有人写了一个bat文件: cd /d D:\lottery\server && python .\main.py 放到了开机自启动里,可是开机的…

【立体几何】如何使用两个正方体(特殊骰子)摆出所有日期1~31

问题 如何使用两个正方体(特殊骰子)摆出所有日期? 解答 下标列举了所有日期 日期十位数个位数011号正方体:02号正方体:02号正方体:11号正方体:1021号正方体:02号正方体:02号正方体:21号正方…

网络安全形势迫在眉睫!云WAF保护私有云安全!

业务上云面临新的WEB安全挑战 目前,所有的组织都在积极地接受企业的“云”,推进数字化变革。在服务云计算和私有云平台构建中,用户除了要面对各种常见的网络攻击,还需要面对虚拟环境下的非授权访问、虚拟机逃逸和敏感信息泄漏等问…

主观评测图生3D之 --- Era3D

文章目录 概述真人测试(一般)动物(猫猫狗狗,不ok)Q版真人(惊艳) 概述 抱抱脸可以直接测试 不过抱抱脸只能够生成多视图图像以及对应的法向图。 评测的话,拿三类我们比较关心的图片…