第 13 章 -Go 语言 接口

在面向对象编程中,接口(Interface)是一种规范的定义,它描述了一组操作方法(方法签名)但不提供具体的实现。接口是实现抽象的一种方式,它允许将行为与实现分离,从而支持灵活的设计和代码复用。下面我将从接口的定义、实现以及接口的多态性三个方面来展开详细讲解。

Go 语言中的接口

Go 语言中的接口是一种类型,它定义了一组方法的集合。接口的主要目的是实现多态性和解耦合。与许多其他语言不同,Go 语言中的接口实现是隐式的,不需要显式声明某个类型实现了某个接口。

接口的定义

在 Go 语言中,接口使用 interface 关键字定义。接口可以包含零个或多个方法签名。一个空的接口 interface{} 可以存储任何类型的值,因为它没有任何方法约束。

type Animal interface {Eat()Sleep()
}

在这个例子中,Animal 接口定义了两个方法 EatSleep,任何实现了这两个方法的类型都可以被视为实现了 Animal 接口。

接口的实现

在 Go 语言中,类型实现接口是隐式的。只要一个类型实现了接口中定义的所有方法,那么这个类型就自动实现了该接口。我们来看一个具体的例子:

type Dog struct{}func (d Dog) Eat() {fmt.Println("Dog is eating")
}func (d Dog) Sleep() {fmt.Println("Dog is sleeping")
}type Cat struct{}func (c Cat) Eat() {fmt.Println("Cat is eating")
}func (c Cat) Sleep() {fmt.Println("Cat is sleeping")
}

在这个例子中,DogCat 类型都实现了 Animal 接口中的 EatSleep 方法,因此它们都实现了 Animal 接口。

接口的多态性

接口的多态性允许我们使用相同的接口调用不同类型的对象。这使得代码更加灵活和可扩展。我们可以通过一个函数来演示这一点:

func FeedAnimal(a Animal) {a.Eat()
}func main() {var d Dogvar c CatFeedAnimal(d) // 输出: Dog is eatingFeedAnimal(c) // 输出: Cat is eating
}

在这个例子中,FeedAnimal 函数接受一个 Animal 类型的参数。无论是 Dog 还是 Cat 对象,只要它们实现了 Animal 接口,就可以传递给 FeedAnimal 函数。

高级特性和最佳实践

1. 接口隔离原则 (ISP)

尽管 Go 语言中的接口实现是隐式的,但仍然可以通过定义小的、特定的接口来遵循接口隔离原则。这有助于减少接口间的依赖关系,使系统更加模块化和易于维护。

type Eater interface {Eat()
}type Sleeper interface {Sleep()
}type Walker interface {Walk()
}type Dog struct{}func (d Dog) Eat() {fmt.Println("Dog is eating")
}func (d Dog) Sleep() {fmt.Println("Dog is sleeping")
}func (d Dog) Walk() {fmt.Println("Dog is walking")
}func main() {var d Dogvar e Eater = dvar s Sleeper = dvar w Walker = de.Eat()s.Sleep()w.Walk()
}

在这个例子中,我们定义了三个小接口 EaterSleeperWalker,每个接口只包含一个方法。Dog 类型实现了这三个接口。

2. 依赖倒置原则 (DIP)

在 Go 语言中,可以通过依赖接口而不是具体实现来实现依赖倒置原则。这使得代码更加灵活和可测试。

type Logger interface {Log(message string)
}type ConsoleLogger struct{}func (c ConsoleLogger) Log(message string) {fmt.Println("Log:", message)
}type FileLogger struct{}func (f FileLogger) Log(message string) {fmt.Println("File Log:", message)
}type Service struct {logger Logger
}func NewService(logger Logger) *Service {return &Service{logger: logger}
}func (s *Service) DoSomething() {s.logger.Log("Doing something...")
}func main() {consoleLogger := ConsoleLogger{}fileLogger := FileLogger{}service1 := NewService(consoleLogger)service2 := NewService(fileLogger)service1.DoSomething() // 输出: Log: Doing something...service2.DoSomething() // 输出: File Log: Doing something...
}

在这个例子中,Service 类型依赖于 Logger 接口,而不是具体的 ConsoleLoggerFileLogger 实现。这使得 Service 更容易测试和扩展。

总结

Go 语言中的接口是一种强大的工具,用于实现多态性和解耦合。通过合理设计和使用接口,可以提高代码的复用性、降低组件间的耦合度、简化单元测试,以及支持更灵活的设计模式。接口的隐式实现特性使得 Go 语言在接口使用上更加简洁和灵活。

当然,我们可以进一步探讨 Go 语言中接口的一些高级特性和应用场景,包括设计模式中的应用、接口在并发编程中的作用,以及接口在微服务架构中的应用等。

设计模式中的接口应用

1. 适配器模式 (Adapter Pattern)

适配器模式用于将一个类的接口转换成客户端所期望的另一个接口。在 Go 语言中,可以通过实现接口来实现适配器模式。

// 目标接口
type Target interface {Request() string
}// 已有的类
type Adaptee struct{}func (a Adaptee) SpecificRequest() string {return "Specific request"
}// 适配器
type Adapter struct {adaptee Adaptee
}func (a Adapter) Request() string {return "Adapted request: " + a.adaptee.SpecificRequest()
}func main() {adaptee := Adaptee{}adapter := Adapter{adaptee: adaptee}var target Target = adapterfmt.Println(target.Request()) // 输出: Adapted request: Specific request
}

在这个例子中,Adapter 类实现了 Target 接口,并委托 Adaptee 类来完成具体的工作。

2. 策略模式 (Strategy Pattern)

策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互换。在 Go 语言中,可以通过接口来实现策略模式。

// 策略接口
type Strategy interface {Execute(data []int) []int
}// 具体策略
type ConcreteStrategyA struct{}func (c ConcreteStrategyA) Execute(data []int) []int {sort.Ints(data)return data
}type ConcreteStrategyB struct{}func (c ConcreteStrategyB) Execute(data []int) []int {sort.Sort(sort.Reverse(sort.IntSlice(data)))return data
}// 上下文
type Context struct {strategy Strategy
}func (c *Context) SetStrategy(s Strategy) {c.strategy = s
}func (c *Context) ExecuteStrategy(data []int) []int {return c.strategy.Execute(data)
}func main() {context := Context{}strategyA := ConcreteStrategyA{}context.SetStrategy(strategyA)fmt.Println(context.ExecuteStrategy([]int{3, 1, 4, 1, 5})) // 输出: [1 1 3 4 5]strategyB := ConcreteStrategyB{}context.SetStrategy(strategyB)fmt.Println(context.ExecuteStrategy([]int{3, 1, 4, 1, 5})) // 输出: [5 4 3 1 1]
}

在这个例子中,Context 类使用 Strategy 接口来执行不同的排序策略。

接口在并发编程中的作用

在 Go 语言中,接口在并发编程中也发挥了重要作用。通过接口,可以更容易地管理和控制并发任务。

1. 使用通道和接口实现并发
// 任务接口
type Task interface {Run() interface{}
}// 具体任务
type AddTask struct {a, b int
}func (t AddTask) Run() interface{} {return t.a + t.b
}type MultiplyTask struct {a, b int
}func (t MultiplyTask) Run() interface{} {return t.a * t.b
}func main() {tasks := []Task{AddTask{3, 4},MultiplyTask{2, 5},}results := make(chan interface{}, len(tasks))for _, task := range tasks {go func(t Task) {results <- t.Run()}(task)}for i := 0; i < len(tasks); i++ {fmt.Println(<-results)}
}

在这个例子中,Task 接口定义了 Run 方法,不同的任务实现了这个方法。通过通道和 goroutines,可以并行执行多个任务并将结果收集到通道中。

接口在微服务架构中的应用

在微服务架构中,接口用于定义服务之间的通信协议。通过明确的服务接口定义,可以确保服务之间的松耦合,提高系统的可扩展性和可维护性。

1. 定义服务接口
// 服务接口
type UserService interface {GetUser(id int) (*User, error)CreateUser(user User) error
}// 用户结构
type User struct {ID   intName string
}// 具体服务实现
type UserServiceImpl struct {db *sql.DB
}func (s *UserServiceImpl) GetUser(id int) (*User, error) {// 查询用户user := User{ID: id, Name: "John Doe"}return &user, nil
}func (s *UserServiceImpl) CreateUser(user User) error {// 创建用户fmt.Printf("Creating user: %v\n", user)return nil
}func main() {userService := &UserServiceImpl{}user, err := userService.GetUser(1)if err != nil {fmt.Println("Error:", err)} else {fmt.Printf("User: %+v\n", user)}newUser := User{Name: "Alice"}err = userService.CreateUser(newUser)if err != nil {fmt.Println("Error:", err)}
}

在这个例子中,UserService 接口定义了用户服务的基本操作,UserServiceImpl 是该接口的具体实现。通过接口,可以轻松地替换不同的实现,例如使用不同的数据库或缓存机制。

接口与错误处理

在 Go 语言中,错误处理通常使用 error 接口。通过自定义错误类型,可以提供更丰富的错误信息。

// 自定义错误类型
type MyError struct {Message string
}func (e *MyError) Error() string {return e.Message
}func main() {err := &MyError{Message: "Custom error message"}if err != nil {fmt.Println("Error:", err.Error())}
}

在这个例子中,MyError 结构体实现了 error 接口的 Error 方法,可以返回自定义的错误信息。

总结

Go 语言中的接口是一种强大的工具,不仅用于实现多态性和解耦合,还在设计模式、并发编程和微服务架构中发挥着重要作用。通过合理设计和使用接口,可以提高代码的复用性、降低组件间的耦合度、简化单元测试,以及支持更灵活的设计模式。接口的隐式实现特性使得 Go 语言在接口使用上更加简洁和灵活。

当然,我们可以继续探讨更多关于 Go 语言中接口的高级特性和应用场景,包括接口在测试中的应用、接口在泛型编程中的作用,以及接口在构建大型系统中的最佳实践等。

接口在测试中的应用

接口在测试中非常重要,因为它们可以轻松地创建模拟对象(mock objects),从而隔离被测试代码与外部依赖。这使得测试更加简单、快速和可靠。

1. 使用接口进行单元测试

假设我们有一个 Database 接口和一个 UserService 类,我们可以通过实现 Database 接口的模拟对象来测试 UserService

// Database 接口
type Database interface {Get(id int) (string, error)Save(name string) error
}// UserService 类
type UserService struct {db Database
}func (s *UserService) GetUser(id int) (string, error) {return s.db.Get(id)
}func (s *UserService) SaveUser(name string) error {return s.db.Save(name)
}// 模拟的 Database 实现
type MockDatabase struct {data map[int]string
}func (m *MockDatabase) Get(id int) (string, error) {name, ok := m.data[id]if !ok {return "", fmt.Errorf("user not found")}return name, nil
}func (m *MockDatabase) Save(name string) error {m.data[len(m.data)] = namereturn nil
}func TestUserService_GetUser(t *testing.T) {mockDB := &MockDatabase{data: map[int]string{1: "Alice"}}userService := &UserService{db: mockDB}name, err := userService.GetUser(1)if err != nil {t.Errorf("expected no error, got %v", err)}if name != "Alice" {t.Errorf("expected Alice, got %s", name)}
}func TestUserService_SaveUser(t *testing.T) {mockDB := &MockDatabase{data: map[int]string{}}userService := &UserService{db: mockDB}err := userService.SaveUser("Bob")if err != nil {t.Errorf("expected no error, got %v", err)}name, _ := mockDB.Get(0)if name != "Bob" {t.Errorf("expected Bob, got %s", name)}
}

在这个例子中,我们创建了一个 MockDatabase 类来模拟 Database 接口的行为。然后在测试中使用这个模拟对象来验证 UserService 的行为。

接口在泛型编程中的作用

虽然 Go 1.18 引入了泛型,但在泛型出现之前,接口是实现泛型行为的主要方式。即使有了泛型,接口仍然是非常有用的工具。

1. 使用接口实现泛型行为
// 泛型接口
type FilterFunc[T any] func(T) bool// 泛型过滤函数
func Filter[T any](items []T, filterFunc FilterFunc[T]) []T {var result []Tfor _, item := range items {if filterFunc(item) {result = append(result, item)}}return result
}func main() {numbers := []int{1, 2, 3, 4, 5}evenNumbers := Filter(numbers, func(n int) bool {return n%2 == 0})fmt.Println(evenNumbers) // 输出: [2 4]strings := []string{"apple", "banana", "cherry"}longStrings := Filter(strings, func(s string) bool {return len(s) > 5})fmt.Println(longStrings) // 输出: ["banana", "cherry"]
}

在这个例子中,我们定义了一个泛型接口 FilterFunc 和一个泛型函数 FilterFilter 函数接受一个切片和一个过滤函数,返回过滤后的切片。

接口在构建大型系统中的最佳实践

在构建大型系统时,合理使用接口可以显著提高代码的可维护性和可扩展性。

1. 明确的接口定义

在设计系统时,应该明确地定义各个组件之间的接口。这有助于确保组件之间的松耦合,使得系统更容易维护和扩展。

// 服务接口
type UserService interface {GetUser(id int) (*User, error)CreateUser(user User) error
}// 数据库接口
type Database interface {Get(id int) (string, error)Save(name string) error
}// 日志记录接口
type Logger interface {Log(message string)
}// 具体实现
type UserServiceImpl struct {db     Databaselogger Logger
}func (s *UserServiceImpl) GetUser(id int) (*User, error) {name, err := s.db.Get(id)if err != nil {s.logger.Log(fmt.Sprintf("Error getting user: %v", err))return nil, err}return &User{ID: id, Name: name}, nil
}func (s *UserServiceImpl) CreateUser(user User) error {err := s.db.Save(user.Name)if err != nil {s.logger.Log(fmt.Sprintf("Error creating user: %v", err))return err}return nil
}func main() {db := &RealDatabase{}logger := &RealLogger{}userService := &UserServiceImpl{db: db, logger: logger}user, err := userService.GetUser(1)if err != nil {fmt.Println("Error:", err)} else {fmt.Printf("User: %+v\n", user)}newUser := User{Name: "Alice"}err = userService.CreateUser(newUser)if err != nil {fmt.Println("Error:", err)}
}

在这个例子中,我们定义了 UserServiceDatabaseLogger 接口,并在 UserServiceImpl 中实现了这些接口。这使得系统更加模块化,每个组件的职责清晰,易于维护和扩展。

2. 依赖注入

依赖注入是一种设计模式,通过将依赖项作为参数传递给构造函数或方法,可以提高代码的可测试性和可维护性。

// 依赖注入
type UserService struct {db     Databaselogger Logger
}func NewUserService(db Database, logger Logger) *UserService {return &UserService{db: db, logger: logger}
}func main() {db := &RealDatabase{}logger := &RealLogger{}userService := NewUserService(db, logger)user, err := userService.GetUser(1)if err != nil {fmt.Println("Error:", err)} else {fmt.Printf("User: %+v\n", user)}newUser := User{Name: "Alice"}err = userService.CreateUser(newUser)if err != nil {fmt.Println("Error:", err)}
}

在这个例子中,NewUserService 函数接受 DatabaseLogger 作为参数,并返回一个 UserService 实例。这使得 UserService 的依赖项可以很容易地被替换,从而提高代码的可测试性和可维护性。

总结

Go 语言中的接口是一种强大的工具,不仅用于实现多态性和解耦合,还在设计模式、并发编程、测试和泛型编程中发挥着重要作用。通过合理设计和使用接口,可以提高代码的复用性、降低组件间的耦合度、简化单元测试,以及支持更灵活的设计模式。接口的隐式实现特性使得 Go 语言在接口使用上更加简洁和灵活。希望这些内容能帮助你在实际项目中更好地利用接口。

接口的定义

接口定义了一组规则,规定了哪些方法必须由实现了该接口的类来实现。在不同的编程语言中,接口的语法可能有所不同,但基本概念是相同的。例如,在Java中,接口使用interface关键字定义,如下所示:

public interface Animal {void eat();void sleep();
}

在这个例子中,Animal是一个接口,它声明了两个方法:eat()sleep()。任何实现了Animal接口的类都必须提供这两个方法的具体实现。

接口的实现

当一个类实现了一个或多个接口时,它必须提供接口中所有抽象方法的具体实现。如果一个类没有实现接口中的所有方法,那么这个类也必须被声明为抽象类。继续上面的例子,我们可以创建一个实现了Animal接口的Dog类:

public class Dog implements Animal {@Overridepublic void eat() {System.out.println("Dog is eating");}@Overridepublic void sleep() {System.out.println("Dog is sleeping");}
}

这里,Dog类实现了Animal接口,并提供了eat()sleep()方法的具体实现。

接口的多态性

多态性是指允许不同类的对象对同一消息作出响应的能力,即同一个接口使用不同的实现版本(多态性)。通过接口实现多态性,可以使得程序设计更加灵活,提高代码的可扩展性和可维护性。

例如,假设我们有一个Animal接口,以及实现了这个接口的不同类如DogCat等。我们可以定义一个接受Animal类型参数的方法,这样无论传入的是Dog对象还是Cat对象,只要它们实现了Animal接口,就可以调用该方法中定义的行为:

public void feedAnimal(Animal animal) {animal.eat();
}

在这个例子中,feedAnimal方法接收一个Animal类型的参数。因为DogCat都是Animal的实现者,所以我们可以向这个方法传递DogCat的对象。这体现了接口的多态性——同一种行为(如eat())可以有不同的表现形式,具体取决于实际传递给方法的对象类型。

接口的使用不仅限于上述示例,它们在软件设计模式中也有广泛的应用,比如适配器模式、策略模式等,这些模式利用接口来达到更好的解耦合、灵活性和重用性的目的。

关于接口的定义、实现及多态性,我们可以进一步探讨一些高级特性和最佳实践,以帮助更深入地理解如何有效使用接口来构建高质量的软件系统。

高级特性和最佳实践

1. 接口隔离原则 (ISP)

接口隔离原则建议客户端不应该依赖它们不使用的接口。换句话说,不要强迫客户程序依赖于它们不用的方法。这可以通过将大接口拆分为多个小接口来实现,每个接口只包含一组相关的功能。这样做可以减少接口间的依赖关系,使系统更加模块化,易于维护。

2. 依赖倒置原则 (DIP)

依赖倒置原则指出,高层模块不应该依赖于低层模块,两者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。这意味着在设计系统时,应尽量让组件依赖于接口而不是具体实现,这样可以增加系统的灵活性和可扩展性。

3. 接口默认方法

从Java 8开始,接口中可以包含默认方法(使用default关键字定义),这使得接口可以在不破坏现有实现类的情况下添加新的方法。默认方法为接口提供了一种向后兼容的方式引入新功能,同时保持接口的灵活性。

public interface Animal {void eat();default void move() {System.out.println("Moving...");}
}

在这个例子中,move是一个默认方法,所有实现了Animal接口的类都会自动获得这个方法的实现,除非它们选择覆盖这个方法。

4. 功能接口与Lambda表达式

在Java 8中,引入了Lambda表达式,它提供了一种简洁的方式来实例化只有一个抽象方法的接口(称为函数式接口)。这种接口通常用于表示一个单一的动作或行为。例如,Runnable接口就是一个典型的功能接口,可以使用Lambda表达式来实现:

Runnable runnable = () -> System.out.println("Running...");
new Thread(runnable).start();

这段代码使用Lambda表达式创建了一个Runnable实例,并启动了一个线程执行这个任务。

5. 使用接口进行单元测试

接口还可以促进单元测试的编写。通过为依赖项定义接口,可以更容易地创建模拟对象(mock objects)来代替真实的依赖,这有助于在不涉及外部系统的情况下测试代码的行为。

结论

接口不仅是实现多态性的基础,也是构建灵活、可维护和可测试的软件系统的重要工具。正确地应用接口设计原则和最佳实践,可以帮助开发人员构建出更加健壮和高效的软件产品。

好的,接下来我们将进一步探讨接口的一些高级特性和应用场景,包括设计模式中的应用、接口在微服务架构中的作用,以及接口如何帮助实现系统解耦等。

设计模式中的接口应用

1. 适配器模式 (Adapter Pattern)

适配器模式允许不兼容的接口一起工作。通过创建一个新的类来作为适配器,这个类实现了目标接口并封装了需要适配的类。这种方式常用于系统升级或集成第三方库时,以解决旧代码与新需求之间的兼容性问题。

2. 策略模式 (Strategy Pattern)

策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户。在这种模式中,接口用来定义一组算法,不同的类则实现了这些算法的具体逻辑。

3. 观察者模式 (Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。在这种模式中,接口用来定义观察者(Observer)和被观察者(Subject)之间的通信协议。

接口在微服务架构中的作用

在微服务架构中,接口扮演着非常重要的角色。每个微服务都暴露了一组API接口,这些接口定义了服务对外提供的功能。通过明确的服务接口定义,各个微服务可以独立开发、部署和扩展,而不会影响其他服务。此外,良好的接口设计还能够促进服务之间的松耦合,提高整个系统的稳定性和可维护性。

接口帮助实现系统解耦

接口通过定义一组行为而不指定其实现细节,促进了系统组件之间的解耦。这意味着,当系统的一个部分发生变化时,不会直接影响到其他部分,从而降低了变更带来的风险。例如,数据库访问层可以通过定义数据访问接口来隐藏具体的数据库操作细节,这样即使更换了数据库,只要保证接口不变,上层业务逻辑就不需要做任何修改。

接口与事件驱动架构

在事件驱动架构中,接口同样发挥着重要作用。通过定义事件处理器接口,可以确保事件处理逻辑的灵活性和可扩展性。当特定事件发生时,系统可以根据预定义的接口调用相应的处理逻辑。这种方式不仅提高了系统的响应速度,还增强了系统的可维护性和可测试性。

总结

接口不仅仅是实现多态性的手段,更是构建高质量软件系统的关键要素之一。通过合理设计和使用接口,可以提高代码的复用性、降低组件间的耦合度、简化单元测试,以及支持更灵活的设计模式。在现代软件开发实践中,接口的概念和应用已经超越了简单的编程技术,成为构建可扩展、高性能和易维护系统的基础。

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

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

相关文章

ABAP开发学习——ST05 ABAP SQL跟踪工具

操作步骤 第一步使用ST05之前&#xff0c;将要查的程序停留想要看的操作的前一步&#xff0c;这里想看到取数操作&#xff0c;所以停留在选择界面 第二步进入ST05 选择SQL Trace 然后激活 第三步去执行程序 第四步ST05取消激活 第五步查看操作 选完时间直接执行

C/C++语言基础--C++模板与元编程系列六,C++元编程相关库的讲解与使用

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 模板与元编程是C的重要特点&#xff0c;也是难点&#xff0c;本人预计将会更新10期左右进行讲解&#xff0c;这是第六期&#xff0c;讲解元编程相关库等&#xff0c;本人感觉这一部分内容还是比较复杂的&am…

uni-app之数据驱动的picker选择器( uni-data-picker)之可以选择到任意级别

背景说明 uni-app 官方的插件市场有数据驱动选择器&#xff0c;可以用作多级分类的场景。本人引入插件后&#xff0c;发现&#xff0c;在h5和微信小程序都只能选择到叶子级。而在给出的官方组件示例中确并非如此。 以选择年级&#xff0c;而不选择班级。然后&#xff0c;想试试…

探索 HTML 和 CSS 实现的蜡烛火焰

效果演示 这段代码是一个模拟蜡烛火焰的HTML和CSS代码。它创建了一个具有动态效果的蜡烛火焰动画&#xff0c;包括火焰的摆动、伸缩和光晕的闪烁。 HTML <div class"holder"><div class"candle"><div class"blinking-glow"&g…

react + ts定义接口类型写法

接口&#xff08;未进行ts定义&#xff09; export async function UserList(params: {// keyword?: string;current?: number;pageSize?: number;},// options?: { [key: string]: any }, ) {return request<API1.UserList>(http://geek.itheima.net/v1_0/mp/artic…

【教程】Ubuntu设置alacritty为默认终端

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景介绍 设置教程 注意事项 背景介绍 alacritty是一个开源的终端&#xff0c;比默认的xterm更好看&#xff0c;甚至编辑文本时候还会代码高亮…

使用Element UI实现前端分页,及el-table表格跨页选择数据,切换分页保留分页数据,限制多选数量

文章目录 一、前端分页1、模板部分 (\<template>)2、数据部分 (data)3、计算属性 (computed)4、方法 (methods) 二、跨页选择1、模板部分 (\<template>)2、数据部分 (data)3、方法 (methods) 三、限制数量1、模板部分 (\<template>)2、数据部分 (data)3、方法…

写给初学者的React Native 全栈开发实战班

React Native 全栈开发实战班 亲爱的同学们&#xff1a; 很高兴在这里与大家相聚&#xff01;我是你们的讲师&#xff0c;将带领大家一起踏上 React Native 移动开发的学习之旅。 为什么选择 React Native&#xff1f; 在这个移动互联网时代&#xff0c;App 开发工程师已经…

StarRocks Summit Asia 2024 全部议程公布!

随着企业数字化转型深入&#xff0c;云原生架构正成为湖仓部署的新标准。弹性扩展、资源隔离、成本优化&#xff0c;帮助企业在云上获得了更高的灵活性和效率。与此同时&#xff0c;云原生架构也为湖仓与 AI 的深度融合奠定了基础。 在过去一年&#xff0c;湖仓技术与 AI 的结…

[CKS] K8S Dockerfile和yaml文件安全检测

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于Dockerfile和yaml文件安全检测的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博…

鸿蒙之多选框(Checkbox)

前言&#xff1a; 控制单个或者多个选项的选中状态&#xff0c;就可以使用 多选框组件 Checkbox:多选框组件CheckboxGroup:多选框组&#xff0c;控制多个多选框 Checkbox: 参数CheckboxOptions说明 名称 类型 必填 描述 name string 否 用于指定多选框名称。一般结合Ch…

CSP/信奥赛C++语法基础刷题训练(8):洛谷P5718:找最小值

CSP/信奥赛C语法基础刷题训练&#xff08;8&#xff09;&#xff1a;洛谷P5718&#xff1a;找最小值 题目描述 给出 n n n 和 n n n 个整数 a i a_i ai​&#xff0c;求这 n n n 个整数中最小值是什么。 输入格式 第一行输入一个正整数 n n n&#xff0c;表示数字个数。…

【云原生系列--Longhorn的部署】

Longhorn部署手册 1.部署longhorn longhorn架构图&#xff1a; 1.1部署环境要求 kubernetes版本要大于v1.21 每个节点都必须装open-iscsi &#xff0c;Longhorn依赖于 iscsiadm主机为 Kubernetes 提供持久卷。 apt-get install -y open-iscsiRWX 支持要求每个节点都安装 N…

【C++】string类(附题)

一、为什么学习string类&#xff1f; 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列 的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&…

前端vue 列表中回显并下拉选择修改标签

1&#xff0c;vue数据列表中进行回显状态并可以在下拉框中选择修改&#xff0c;效果如下 2&#xff0c;vue 页面关键代码 <el-table-column label"审核" align"center" class-name"small-padding fixed-width" prop"status" >&…

Brave127编译指南 Windows篇:部署Node.js(五)

1. 概述 在Brave浏览器的编译过程中&#xff0c;Node.js扮演着关键角色。作为一个建立在Chrome V8引擎之上的JavaScript运行时环境&#xff0c;Node.js为开发者提供了在服务器端执行JavaScript代码的能力。它的非阻塞、事件驱动架构使其特别适合构建高性能、可扩展的网络应用。…

嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机

引言&#xff1a;主要针对于嵌入式全栈内容的知识点汇总并对于linux等相关驱动知识点进行串联&#xff0c;用大家参考学习&#xff0c;并用到了嘉立创提供的泰山派RK3566作为学习的主控。 实物演示如下所示&#xff1a; 目录 一、硬件设计 1.转接电路 2.背光电路 3.音频接…

MySQL:数据库的约束

约束类型 NOT NULL - 指示某列不能存储 NULL 值。 UNIQUE - 保证某列的每行必须有唯一的值。 DEFAULT - 规定没有给列赋值时的默认值。 PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列&#xff08;或两个列多个列的结合&#xff09;有唯一标识&#xff0c;有助于更容易更…

Ps:OpenColorIO 设置

Ps菜单&#xff1a;编辑/OpenColorIO 设置 Edit/OpenColorIO Settings 在专业的图像编辑和色彩管理工作流程中&#xff0c;准确的色彩呈现和转换至关重要。OpenColorIO&#xff08;OCIO&#xff09; 是一种开源的色彩管理框架&#xff0c;广泛应用于影视、动画和视觉特效行业。…

datastage在升级版本到11.7之后,部分在11.3上正常执行的SP报错SQLSTATE = 22007: 本机错误代码 = -180

在升级版本到11.7之后&#xff0c;部分在11.3上正常执行的SP开始报错&#xff0c;报的SQL错误是时间参数问题&#xff0c;但是一样的SP可以直接call sp执行&#xff0c;也可以手动调用作业执行&#xff0c;只有设置定时调度时作业会报错&#xff0c; CALLXXX.XXX(1,CURRENT TIM…