【Go语言精进之路】构建高效Go程序:掌握变量、常量声明法则与iota在枚举中的奥秘

在这里插入图片描述

🔥 个人主页:空白诗

在这里插入图片描述

文章目录

    • 引言
    • 一、变量
      • 1.1 基础知识
      • 1.2 包级变量的声明形式深入解析
        • 📌 声明并同时显式初始化
        • 📌 声明但延迟初始化
        • 📌 声明聚类与就近原则
      • 1.3 局部变量的声明形式深入探讨
        • 📌 延迟初始化的局部变量声明
        • 📌 显式初始化的局部变量与短变量声明
        • 📌 分支控制中的短变量声明
    • 二、常量
      • 2.1 Go语言常量溯源:从C语言到Go
        • 📌 C语言中的常量
        • 📌 Go语言中的常量进化
      • 2.2 有类型常量带来的烦恼
        • 📌 类型转换的显式性
        • 📌 限制通用性
        • 📌 类型错误的频繁出现
      • 2.3 无类型常量消除烦恼,简化代码
        • 📌 动态类型推导
        • 📌 增强通用性和代码复用
        • 📌 减少类型错误
    • 三、使用 iota 实现枚举常量
      • 3.1 基础用法:自动递增
      • 3.2 高级用法:表达式、继承、显式赋值、空标识符与重置
    • 四、总结

引言

Go 语言作为现代编程领域的重要成员,对变量和常量的处理体现了静态类型语言的精髓。本文深入剖析了 Go 语言中变量的基础知识、包级与局部变量的声明形式,以及常量的设计哲学与实践中的考量,旨在为开发者揭示 Go 在数据存储与类型管理方面的独特机制与优化策略。

在这里插入图片描述


一、变量

1.1 基础知识

变量是编程语言的基本构成元素,它们担当存储信息与实现数据操作的重任。Go语言中,变量声明是一项核心机制,深刻反映了语言本身的设计原则:追求简洁性、确保运行效率及强化代码的安全性。恰当的变量声明策略,对于提升程序代码的可读性、维护便捷性以及执行效能具有不可或缺的作用。

在这里插入图片描述

Go语言体系中,变量是存储数据的基本单元,其核心功能在于保存程序运行过程中的信息。每个变量都被赋予了特定的数据类型,这些类型涵盖了诸如整数(int)浮点数(float)字符串(string) 等多种基本类型以及其他复合类型。数据类型定义了变量能够存储值的范围和类型,确保了数据的准确性和一致性。

Go 作为一种静态类型语言,在程序编译阶段就要求明确指定每个变量的类型。这意味着:

  • 类型固定性:一旦为变量指定了一个类型,如intstring,该变量就只能存储该类型的数据,无法在程序运行过程中改变其类型。
  • 编译时检查:编译器会在编译阶段检查所有变量的使用是否符合其声明的类型,这样可以提前发现类型不匹配的错误,避免运行时出现意外行为。
  • 性能优势:由于类型在编译时已确定,编译器可以进行更多的优化,提升程序的执行效率。

例如,声明一个整型变量counter并赋值为10,其类型int在编译时就需要被明确指定,并且后续尝试给counter赋值为字符串将导致编译错误:

var counter int = 10
// counter = "This will not compile" // 错误:类型不匹配

这种静态类型的特性,促使开发者在编码初期就必须仔细考虑数据的表示,促进了代码的严谨性和可维护性。

Go中,变量除了按数据类型划分外,还可以根据其声明的位置和作用域分为两大类:包级变量局部变量

1.2 包级变量的声明形式深入解析

包级变量定义在包作用域内的变量,它们具有全局可见性,对包内的所有函数开放访问权限。这类变量通常用于存储那些在包的多个组件间共享的状态或配置信息。

📌 声明并同时显式初始化

当你希望变量在声明时即赋予一个具体的初始值,可以采用这种方式。这不仅明确了变量的用途,有时还能帮助减少因未初始化变量而引发的错误。

package main

var version string = "1.0.0" // 包级变量声明并显式初始化为版本号
📌 声明但延迟初始化

在某些场景下,你可能知道某个变量将被使用,但其确切的初始化值在声明时刻还未知或不适合立即设定。此时,你可以先声明变量而不进行初始化Go会自动为这些变量赋予其类型的零值(如int的零值为0boolfalse等)。

var debugMode bool // 声明一个布尔型包级变量,初始化为false(零值)
📌 声明聚类与就近原则

Go允许在一个var声明中声明多个变量,这称为声明聚类,可以使得代码更为紧凑。此外,Go遵循就近原则,如果在更小的作用域内重新声明了同名变量,那么原始的包级变量在该作用域内将被遮蔽。

var (
    connectionTimeout time.Duration = 5 * time.Second // 初始化连接超时时间
    maxAttempts int = 3                        // 最大尝试次数
    // ...其他变量声明
)

func handleRequest() {
    var maxAttempts int = 10 // 函数内重新声明maxAttempts,遮蔽包级变量
    // 此处的maxAttempts指的是局部变量10
}

在上面的例子中,handleRequest函数内部重新声明了一个名为maxAttempts的局部变量,这表明在该函数内部,maxAttempts引用的是局部变量10,而非包级变量3,展示了就近原则的应用。

1.3 局部变量的声明形式深入探讨

局部变量作为函数或代码块内部的存储单元,其生命期严格限定于声明它们的上下文内,这有助于保持代码的模块化和清晰度。接下来,我们将详细探讨局部变量的几种声明形式及其在实际编程中的应用策略。

📌 延迟初始化的局部变量声明

在某些情况下,你可能需要 先声明变量,稍后再根据逻辑流程决定其初始化值。这时,采用传统的var声明形式是合适的。

func calculateSum(numbers []int) int {
    var sum int // 声明局部变量sum但不立即初始化
    for _, number := range numbers {
        sum += number // 在循环中累加求和
    }
    return sum
}
📌 显式初始化的局部变量与短变量声明

Go推崇简洁性,特别是在类型可以从初始值直接推断的情况下,推荐使用短变量声明(:=)来声明并初始化局部变量。这种方式不仅减少了代码量,也增强了代码的可读性。

func greetUser(name string) {
    greeting := "Hello, " + name + "!" // 简洁声明并初始化
    fmt.Println(greeting)
}
📌 分支控制中的短变量声明

在条件语句或循环体中,利用短变量声明可以有效地管理临时变量,避免不必要的变量作用域扩散,使得代码更加紧凑且易于理解。

func processData(inputData map[string]int) {
    if value, exists := inputData["key"]; exists {
        // 使用value,已知存在
    } else {
        // 在else块内部声明新的value,避免污染外部作用域
        value := getDefaultData()
        // 处理defaultValue
    }
}

func getDefaultData() int {
    return 0
}

总结而言,Go语言在局部变量声明上提供了丰富的机制,旨在提升代码的简洁性和执行效率。无论是通过传统的var声明进行延迟初始化,还是利用类型推断的短变量声明来简化代码,亦或是巧妙地在分支结构中应用短变量声明以增强代码逻辑的清晰度,都是为了帮助开发者编写出更加高效、易读、易维护的Go程序。


二、常量

2.1 Go语言常量溯源:从C语言到Go

在探索Go语言常量的设计理念之前,回顾一下C语言中的常量概念是十分有益的,因为C语言对许多现代编程语言的常量和变量处理方式有着深远的影响。

在这里插入图片描述

📌 C语言中的常量

C语言中,常量分为以下几类:

  • 字面常量:直接写在代码中的固定值,如5, "Hello, World!", true等,它们没有名字,直接用于表达式。
  • 符号常量:通过#define预处理器指令定义,给一个固定值赋予一个名字,如#define PI 3.14159。符号常量在编译前会被替换为对应的值,因此不占用运行时内存,也没有类型信息。

C语言的常量系统相对简单,但也存在一些局限性:

  • 类型不安全:符号常量(#define)本质上是一种文本替换,编译器不做类型检查,可能导致类型错误。
  • 缺乏类型灵活性:字面常量有固定的类型,而符号常量完全无类型,这限制了它们的使用场景。
  • 表达式能力有限:C语言的常量表达式在编译时计算的能力有限,不支持复杂的计算或类型推导。
📌 Go语言中的常量进化

Go 语言设计者在设计常量系统时,既借鉴了C语言的优点,也针对其局限性进行了改进:

  • 类型安全与灵活性Go中的常量通过const关键字声明,不仅支持基本类型,还可以是用户自定义类型。与C语言不同,Go的常量是有类型的,这保证了类型安全,同时允许在编译时进行类型推导和转换。

  • 强大的编译时计算能力Go支持在常量声明中使用几乎所有的算术和逻辑运算符,甚至支持位操作,使得编译时计算能力大大增强。这意味着可以在编译阶段完成更多工作,减少运行时负担。

  • iota与枚举Go引入了iota这个特殊的常量生成器,极大地简化了枚举类型的定义。iota在每个const声明块中自动递增,为创建有序的常量集合提供了一种简洁的方式。

  • 无类型常量与类型推导Go允许定义无类型常量,这些常量在使用时会根据上下文自动推断类型。这种机制既保留了灵活性,又保持了类型安全,减少了因类型转换带来的代码复杂度。

通过这些设计,Go语言的常量系统在继承C语言简单直接特性的基础上,进一步提升了类型安全、表达能力和编译时计算的灵活性,更好地满足了现代软件开发的需求。

2.2 有类型常量带来的烦恼

在编程语言的领域里,有类型常量(Typed Constants)扮演着双重角色:一方面,它们为程序设计引入了清晰的明确性,确保了数据的安全性;另一方面,在诸如 Go 或某些特定用途的 C++ 等类型系统严格的语言中,它们也带来了一系列潜在的挑战与烦恼。以下是几个关键方面的深入探讨。

📌 类型转换的显式性

有类型常量的一个核心烦恼在于跨类型操作时的显式类型转换需求。这意味着,当有类型常量参与不同数据类型间的运算或赋值时,程序员必须手动执行类型转换,以确保类型兼容性。这样做虽确保了类型安全,却可能增加代码的复杂度,尤其是在涉及多步骤计算或复杂表达式时。

package main

import "fmt"

func main() {
	const intConstant int = 42
	const floatConstant float64 = 3.14

	// 显示转换intConstant为float64以进行加法操作
	sum := floatConstant + float64(intConstant)
	fmt.Println(sum) // 输出: 45.14
}

此例中,即使目的很明确——将intConstantfloatConstant相加,也必须通过float64(intConstant)显式转换类型,增加了实现的繁琐度。

📌 限制通用性

有类型常量的另一个局限在于其固定性一旦定义了常量的类型,该类型便不可更改,这在一定程度上限制了常量在多上下文中的复用性。特别是在需要适应多种类型处理逻辑的场景,这可能导致需要定义多个相同值但类型不同的常量。

package main

import (
	"fmt"
)

func processIntValue(i int) {
	fmt.Println("Processing an integer:", i)
}

func processFloatValue(f float64) {
	fmt.Println("Processing a float:", f)
}

func main() {
	const myConst int = 10

	// 为了适应不同函数的参数类型,需要进行类型转换
	processFloatValue(float64(myConst)) // 需要转换
}

尽管myConst的值对于processIntValueprocessFloatValue都适用,但其定义为int类型,迫使我们在调用processFloatValue时进行类型转换,体现了类型固定性对通用性的影响。

📌 类型错误的频繁出现

在大型项目开发中,由于有类型常量严格类型约束,开发者在不恰当使用时容易遇到编译时类型不匹配的错误,尤其当常量被广泛应用时,此类错误的排查可能变得相当耗时且繁琐。

package main

import (
	"fmt"
)

const strConstant string = "GoLang"

func expectsInt(i int) {
	fmt.Println("Received int:", i)
}

func main() {
	// 这里尝试赋值会导致编译错误,因为类型不匹配
	// expectsInt(strConstant) 
}

尝试将strConstant(一个字符串类型常量)传递给期望整型参数的expectsInt函数,编译器会立即指出类型不匹配的错误,虽然这保障了类型安全,但也意味着在编写和维护时必须时刻警惕类型的一致性。

综上所述,有类型常量的这些“烦恼”实际上是类型安全机制的双刃剑,它们确保了程序的健壮性,但同时也对开发者提出了更高的要求,即在享受类型安全带来的好处的同时,也要妥善处理由此产生的额外复杂性。

2.3 无类型常量消除烦恼,简化代码

相较于有类型常量可能带来的种种挑战,无类型常量(Untyped Constants) 在Go语言中提供了一种更为灵活和简洁的解决方案,有效消除了上述烦恼,让代码编写和维护变得更加顺畅。

📌 动态类型推导

无类型常量最大的特点在于其能够在赋值或参与表达式时根据上下文自动推导类型,从而免去了显式类型转换的需要。这不仅减少了代码量,也提升了代码的可读性和维护性。

package main

import "fmt"

func main() {
	const untypedConst = 42 // 无类型常量

	// 自动推导为int类型
	intVar := untypedConst
	fmt.Println("As int:", intVar)

	// 自动推导为float64类型
	floatVar := untypedConst + 3.14
	fmt.Println("As float64:", floatVar)
}

在这个例子中,untypedConst作为无类型常量,既可以直接赋值给int类型的变量,也能参与浮点数运算自动转化为float64类型,大大简化了代码并提高了灵活性。

📌 增强通用性和代码复用

无类型常量的另一大优势在于其泛用性由于没有固定类型,它们可以在多种类型上下文中复用,无需为每个上下文单独定义类型化的常量,这对于需要跨类型共享相同基础值的场景尤为有用

package main

import "fmt"

func processAnyTypeValue[T any](v T) {
	fmt.Printf("Processing value of type %T: %v\n", v)
}

func main() {
	const universalConst = 10 // 无类型常量

	// 直接用于不同类型的函数调用,无需转换
	processAnyTypeValue(universalConst)
	processAnyTypeValue(float64(universalConst)) // 显示转换示例,实际并不需要,仅展示灵活性
}

通过泛型函数processAnyTypeValue的演示,可以看到无类型常量universalConst能够轻松应用于各种类型参数,显著增强了代码的通用性和复用性。

📌 减少类型错误

由于无类型常量在使用时由编译器根据上下文自动推导类型,这在很大程度上减少了由于类型不匹配导致的编译错误。开发者不再需要担心因忘记类型转换而引发的错误,提高了开发效率和代码的稳定性。

通过以上分析与示例,可以看出,无类型常量通过其动态类型推导的特性,有效解决了有类型常量带来的类型转换显式性、通用性限制以及类型错误频繁出现等问题,从而简化了代码,提升了编程体验。在 Go 语言中明智地利用无类型常量,能够让我们编写出更加清晰、灵活和高效的代码。


三、使用 iota 实现枚举常量

Go 语言中,iota是一个非常特殊的常量生成器,它在常量定义中自动递增,为开发者提供了一种极其优雅的方式来定义枚举类型的常量序列。通过iota,我们可以避免手动指定每个常量的值,从而简化代码,减少错误,提高可读性。下面是iota在实现枚举常量中的应用细节和示例。

在这里插入图片描述

3.1 基础用法:自动递增

package main

import "fmt"

// 利用const关键字定义枚举常量,并利用iota实现自动递增
const (
	// 首个常量未直接指定值,iota默认从0开始
	Sunday = iota
	Monday	  // 自动递增到1
	Tuesday   // 自动递增到2
	Wednesday // 自动递增到3
	Thursday  // 自动递增到4
	Friday    // 自动递增到5
	Saturday  // 自动递增到6
)

func main() {
	fmt.Println("Sunday:", Sunday)     // 输出: Sunday: 0
	fmt.Println("Monday:", Monday)     // 输出: Monday: 1
	fmt.Println("Saturday:", Saturday) // 输出: Saturday: 6
}

这段代码展示了如何使用iota来定义枚举类型的常量。下面是对代码的简要说明和其输出结果的解释:

  • 定义枚举: 通过const关键字定义了一组表示星期的枚举常量。每个常量都隐式地被赋予了一个递增的整数值,起始于0,这是iota的默认行为。

  • iota的使用:

    • Sunday = iota 表示Sunday的值为0,因为这是iota第一次出现的地方,默认从0开始。
    • 随后,对于MondaySaturday,每遇到一个新的常量声明行,iota的值就自动递增1。因此,Monday是1,Tuesday是2,依此类推,直到Saturday为6。
  • 代码执行结果:

    • fmt.Println("Sunday:", Sunday) 输出 Sunday: 0
    • fmt.Println("Monday:", Monday) 输出 Monday: 1
    • fmt.Println("Saturday:", Saturday) 输出 Saturday: 6

这段代码简洁明了地展示了如何利用iota来避免为每个枚举值手动赋值,提高了代码的简洁性和维护性。这种枚举方式在Go语言中非常常见,尤其适用于那些需要定义一系列相关常量的场景。

3.2 高级用法:表达式、继承、显式赋值、空标识符与重置

package main

import "fmt"

const (
	Red = iota   // iota初始为0,所以Red的值为0  
	Green   // iota递增到1,所以Green的值为1 
	Blue	// iota递增到2,所以Blue的值为2
	Yellow = iota * 10	// iota此时为3,所以Yellow的值为3 * 10 = 30
	Purple	// iota此递增到4,由于没有显式赋值,所以继承上方的iota * 10规则,Purple的值为4 * 10 = 40
	Black = iota 	 // 显式赋值为iota,此时iota值为5,所以Black为5
	_                // 空标识符,表示忽略该值 6
	White = iota + 9 // iota为7,显式iota加9之后变为16
	_                // 16+1=17
	Cyan  = iota     // 重置为iota本身的值 9
)

func main() {
	fmt.Println("Red:", Red) // 输出为0
	fmt.Println("Green:", Green)  // 输出为1
	fmt.Println("Blue:", Blue) // 输出为2
	fmt.Println("Yellow:", Yellow) // 输出为30
	fmt.Println("Purple:", Purple) // 输出为40
	fmt.Println("Black:", Black)  // 输出为5
	fmt.Println("White:", White) // 输出为16
	fmt.Println("Cyan:", Cyan) // 输出为9
}

在Go语言的const块中,iota是一个预定义的、只能在const声明中使用的计数器,初始值为0,并在每个const规范组(即没有新的const关键字开始的地方)的每行常量声明中递增。这种特性允许你创建一系列递增或基于特定规则的常量值。

在上述代码中,iota的用法展示了它的基本和高级特性:

  1. 初始化和递增

    • Red = iotaiota初始为0,所以Red的值为0。
    • Green:没有显式赋值,iota递增到1,所以Green的值为1。
    • Blue:同样,iota递增到2,Blue的值为2。
  2. 表达式和继承

    • Yellow = iota * 10:此时iota为3,所以Yellow的值为3 * 10 = 30
    • Purple:没有显式赋值,但由于Purple紧跟在Yellow之后,并且Yellow使用了iota * 10的表达式,所以Purple继承了这个表达式并使用当前的iota值(4)进行计算,得到4 * 10 = 40
  3. 显式赋值

    • Black = iota:这里明确地将Black赋值为当前的iota值,即5(因为Purple之后iota递增了)。
  4. 空标识符

    • _:空标识符用于忽略某个值。在这里,它用于跳过iota的当前值(6),而不将其分配给任何常量。
  5. 重置和再次递增

    • White = iota + 9:此时iota为7(因为_之后递增了),所以White的值为7 + 9 = 16
    • 紧接着的_再次使iota递增到8,但这个值被忽略了。
    • Cyan = iota:此时iota为9,所以Cyan的值为9。

注意,在 Go 中,const块中的iota块作用域的,即如果你开始一个新的const块(即新的一组常量声明,前面有const关键字),iota会被重置为0。但在同一个const块中,即使中间插入了其他非常量声明(如变量声明或函数声明),iota的递增也会继续。

此外,iota的使用通常用于创建一组逻辑上相关或按某种模式递增的常量值,使得代码更加清晰和易于维护。然而,过度使用或滥用iota可能会使代码难以阅读和理解,所以应该谨慎使用。


四、总结

Go语言在变量常量的处理上展现了其卓越的设计和强大的功能:

  • 通过静态类型系统Go 确保了变量声明的严谨性和类型安全,减少了运行时错误。包级变量局部变量的灵活声明方式,包括显式初始化和类型推断的短变量声明,不仅增强了代码的可读性和可维护性,还提高了执行效率。
  • 常量管理上,Go通过有类型常量无类型常量的结合,以及引入独特的iota计数器,为开发者提供了一种简洁而强大的枚举实现方式。iota的高级运用,如表达式结合、值重置和跳过特定值等,进一步丰富了枚举常量的定义方式,使Go 成为编写高质量、高性能软件的理想选择。

📌 变量声明与管理

  • Go语言通过静态类型系统强化了变量声明的严谨性,要求在编译阶段明确指定变量类型,从而确保了类型安全和早期错误检测。
  • 包级变量具有全局可见性,用于跨函数共享数据,可通过显式初始化或声明后赋零值来定义,支持在同一var语句中声明多个变量体现声明聚类。
  • 局部变量限于函数或代码块内,通过传统var声明、类型推断的短变量声明(:=)等方式灵活定义,增强了代码简洁性和执行效率,尤其是在分支控制中展现了短变量声明的价值。

📌 常量的演变与优化

  • C语言常量设计的回顾到Go语言的改进,突出了Go在常量系统上的进步,如类型安全、强大的编译时计算能力、以及通过iota实现的枚举简化。
  • 有类型常量虽然确保了数据的安全性和精确性,但可能伴随显式类型转换的繁琐、通用性受限及类型错误问题。
  • 无类型常量通过自动类型推导简化了代码,提高了灵活性和复用性,减轻了类型转换的负担,特别是在多类型上下文中展现了其价值。

📌 iota与枚举常量的高级运用

  • iota作为Go中独特的常量计数器,自动递增并在常量声明中提供了一种简洁的枚举实现方式,支持表达式结合、值重置、跳过特定值等高级特性。
  • 通过案例分析,展示了如何利用iota不仅实现基础的递增枚举,还能通过表达式定义复杂的枚举逻辑,如乘法增长、显式赋值重置iota计数等,极大丰富了枚举常量的定义方式和应用场景。

综上所述,Go 语言在变量和常量的处理上,通过静态类型系统灵活的声明形式、以及iota在枚举中的创新应用,体现了对代码清晰度、类型安全、执行效率的高度重视,同时也兼顾了开发者的便利性和编程的灵活性。这些特性共同支撑了 Go 语言成为编写高质量、高性能软件的优选工具。


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【原创教程】MES服务器与成品打标机控制说明

1 实现的功能及应用的场合 MES即制造执行系统(manufacturing execution system,简称MES),即在加强MRP计划的执行功能,把MRP计划同车间作业现场控制,通过执行系统联系起来。 MES是一个生产管理智能化的一个系统,是用于生产时记录数据、产量等信息的智能管理系统。 该项…

go语言基于Gin集成后台管理系统开发定时任务管理cron/v3好用又好看

系统目前是支持两种定时类型,一种是函数类型,一种是接口类型,来支持多样的业务;时间周期可视化选择,方便设定执行周期。框架UI漂亮,添加管理定时任务设置简单,客户都可以做自己调整执行时间周期…

LLC开关电源开发:第一节,LLC原理概述

第一节,LLC原理概述文章目录 一、LLC概述二、LLC电路拓扑1.电路拓扑2.电路工作原理3.电路原理分析 总结 一、LLC概述 LLC电路,是一种通过控制开关频率(频率调节)来实现输出电压恒定的谐振电路,它包括一个电感L、一个电…

transfomer中attention为什么要除以根号d_k

简介 得到矩阵 Q, K, V之后就可以计算出 Self-Attention 的输出了,计算的公式如下: A t t e n t i o n ( Q , K , V ) S o f t m a x ( Q K T d k ) V Attention(Q,K,V)Softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)Softmax(dk​ ​QKT​)V 好处 除以维…

算法每日一题(python,2024.05.31)

题目来源(力扣. - 力扣(LeetCode),简单) 解题思路: 二次遍历,第一次遍历用哈希表记录每个字母的出现次数,出现一次则将它的value值赋为True,将它的下标赋为key值&#x…

leetcode74搜索二维矩阵

题目 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 fa…

LeetCode-47 全排列Ⅱ

LeetCode-47 全排列Ⅱ 题目描述解题思路代码说明 题目描述 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 示例 : 输入:nums [1,1,2]输出: [[1,1,2], [1,2,1], [2,1,1]] b站题目解读讲的不好&…

充电宝哪个牌子好?怎么选充电宝?压箱底充电宝购买指南大全!

充电宝作为我们日常生活中不可或缺的便携式电源之一,市场上品牌众多、种类繁多。对于消费者来说,如何选择适合自己的充电宝成为一个值得重视的问题。有的充电宝厂家为节省成本“偷工减料”,使用劣质电池,以次充好、参数造假等现象…

Win10安装TensorRT

目录 什么是TensorRT 下载TensorRT 安装TensorRT 拷贝文件 安装whl文件 验证是否安装成功 什么是TensorRT TensorRT是由Nvidia推出的C语言开发的高性能神经网络推理库,是一个用于生成部署的优化器和运行时引擎。和cudnn类似,但它不支持训练&#xff…

Mysql(一)查询Sql是如何执行的

Hello,大家好我是极客涛😎,我最近在整理Mysql相关的知识点,所以准备开启一个Mysql的主线任务,大概耗时3周左右,整个节奏还是由浅入深,主要包括Mysql的架构、事务实现、索引组织形式、SQL优化、日…

kettle 使用动态变量名定义变量

name是变量,value 值也是变量 我需要把name作为变量名,value作为变量值; 在kettle中,使用javascript脚本 key与lastVsxzl都是变量 //Script here setVariable(key,lastVsxzl,r);var rgetVariable(key,r); Demo 1、从记事本里面…

sensitive-word 敏感词 v0.16.1 新特性支持字典内存资源释放

敏感词系列 sensitive-word-admin 敏感词控台 v1.2.0 版本开源 sensitive-word-admin v1.3.0 发布 如何支持分布式部署? 01-开源敏感词工具入门使用 02-如何实现一个敏感词工具?违禁词实现思路梳理 03-敏感词之 StopWord 停止词优化与特殊符号 04-…

【第十三节】C++控制台版本坦克大战小游戏

目录 一、游戏简介 1.1 游戏概述 1.2 知识点应用 1.3 实现功能 1.4 开发环境 二、项目设计 2.1 类的设计 2.2 各类功能 三、程序运行截图 3.1 游戏主菜单 3.2 游戏进行中 3.3 双人作战 3.4 编辑地图 一、游戏简介 1.1 游戏概述 本项目是一款基于C语言开发的控制台…

linux--------线程的同步和互斥

前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、线程互斥 (1)互斥: 任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用 要了解互…

fastjson 泛型转换问题(详解)

系列文章目录 附属文章一:fastjson TypeReference 泛型类型(详解) 文章目录 系列文章目录前言一、代码演示1. 不存在泛型转换2. 存在泛型转换3. 存在泛型集合转换 二、原因分析三、解决方案1. 方案1:重新执行泛型的 json 转换2. …

使用Python突破网站验证码限制

之前有小伙伴说,在web自动化的过程中,经常会被登录的验证码给卡住,不知道如何去通过验证码的验证,今天专门给大家来聊聊验证码的问题。 常见的验证码一般分为两类,一类是图文验证码,一类是滑块验证码&#…

c#基础()

学习目标 了解:嵌套类,匿名类,对象初始化器 重点:类的定义以及对象,构造方法,this和static关键字 掌握:面向对象的概念,访问修饰符,垃圾回收 面向对象 面向对象的概…

面试题:SpringBoot启动流程

具体步骤 新建一个Spring应用程序 (new springApplication()): 确认web应用的类型加载ApplicationContextInitializer加载ApplicationListener记录主启动类 运行应用程序(.run): 准备环境对象Environment,用于加载…

Java学习【String类详解】

Java学习【String类详解】 String的介绍及定义方式String类型的比较String类型的查找charAt()访问字符indexOf()查找下标 转化和替换数值和字符串转化大小写的转换字符串转数组格式化替换 字符串的拆分和截取split()拆分substring()截取trim()去除两边空格 StringBuilder和Stri…

09Linux GDB学习笔记

Linux GDB使用 目录 文章目录 Linux GDB使用先编译文件1.检查安装1.1 安装GDB 2.启动GDB3.退出GDB4.设置断点4.1 在指定行号处设置断点4.2 在指定函数名处设置断点4.3 在指定源文件和行号处设置断点 4.4查看断点信息4.5删除断点5.运行5.1 <font color#ff0000>逐过程&am…