当前位置: 首页 > news >正文

[Golang]多返回值函数、defer关键字、内置函数、变参函数、类成员函数、匿名函数

函数

文章目录

  • 函数
    • 多返回值函数
    • 按值传递、按引用传递
    • 类成员函数
    • 改变外部变量
    • 变参函数
    • defer和追踪
      • 说明
      • 一些常见操作
        • 实现
      • 使用`defer`实现代码追踪
      • 记录函数的参数和返回值
    • 常见的内置函数
    • 将函数作为参数
    • 闭包
      • 实例
      • 闭包将函数作为返回值
    • 计算函数执行时间
    • 使用内存缓存来提升性能

参考书:《the way to go》

Go 里面有三种类型的函数:

  • 普通的带有名字的函数
  • 匿名函数或者lambda函数
  • 方法

没有参数的函数通常被称为 niladic 函数 (niladic function)

函数可以将其他函数调用作为它的参数,只要这个被调用函数的返回值个数、返回值类型和返回值的顺序与调用函数所需求的实参是一致的

假设 f1 需要 3 个参数 f1(a, b, c int),同时 f2 返回 3 个参数 f2(a, b int) (int, int, int),就可以这样调用 f1f1(f2(a, b))

Go不允许函数重载,因为多余的类型匹配会影响性能

就是以函数作为返回类型。这种类型的声明要写在函数名和可选的参数列表之后,例如:

func FunctionName (a typea, b typeb) typeFunc

可以定义没有形参名的函数

func f(int, int, float64)

你可以在函数体中的某处返回使用类型为 typeFunc 的变量 var

return var

可拥有多种返回值

返回类型之间需要使用逗号分割,并使用小括号 () 将它们括起来,如:

func FunctionName (a typea, b typeb) (t1 type1, t2 type2)

返回的形式:

return var1, var2

这种多返回值一般用于判断某个函数是否执行成功 (true/false) 或与其它返回值一同返回错误消息

函数也可以以申明的方式被使用,作为一个函数类型,就像:

type binOp func(int, int) int

在这里,不需要函数体 {}

函数是一等值 (first-class value):它们可以赋值给变量,就像 add := binOp 一样。

这个变量知道自己指向的函数的签名,所以给它赋一个具有不同签名的函数值是不可能的。

函数值 (functions value) 之间可以相互比较:如果它们引用的是相同的函数或者都是 nil 的话,则认为它们是相同的函数。函数不能在其它函数里面声明(不能嵌套),不过我们可以通过使用匿名函数(参考)来破除这个限制。

目前 Go 没有泛型 (generic) 的概念,也就是说它不支持那种支持多种类型的函数。不过在大部分情况下可以通过接口 (interface),特别是空接口与类型选择(type switch)与/或者通过使用反射(reflection)来实现相似的功能。使用这些技术将导致代码更为复杂、性能更为低下,所以在非常注意性能的的场合,最好是为每一个类型单独创建一个函数,而且代码可读性更强

多返回值函数

多值返回是 Go 的一大特性,为我们判断一个函数是否正常执行提供了方便。

我们通过 return 关键字返回一组值。事实上,任何一个有返回值(单个或多个)的函数都必须以 returnpanic结尾

如果一个函数需要返回四到五个值,我们可以传递一个切片给函数(如果返回值具有相同类型)或者是传递一个结构体(如果返回值具有不同的类型)。因为传递一个指针允许直接修改变量的值,消耗也更少

实例:

如下里的函数带有一个 int 参数,返回两个 int 值;其中一个函数的返回值在函数调用时就已经被赋予了一个初始零值。

getX2AndX3getX2AndX3_2 两个函数演示了如何使用非命名返回值与命名返回值的特性。当需要返回多个非命名返回值时,需要使用 () 把它们括起来,比如 (int, int)

命名返回值作为结果形参 (result parameters) 被初始化为相应类型的零值,当需要返回的时候,我们只需要一条简单的不带参数的 return 语句。需要注意的是,即使只有一个命名返回值,也需要使用 () 括起来

package mainimport "fmt"var num int = 10
var numx2, numx3 intfunc main() {numx2, numx3 = getX2AndX3(num)PrintValues()numx2, numx3 = getX2AndX3_2(num)PrintValues()
}func PrintValues() {fmt.Printf("num = %d, 2x num = %d, 3x num = %d\n", num, numx2, numx3)
}func getX2AndX3(input int) (int, int) {return 2 * input, 3 * input
}func getX2AndX3_2(input int) (x2 int, x3 int) {x2 = 2 * inputx3 = 3 * input// return x2, x3return
}

输出结果:

image-20231022193021981

按值传递、按引用传递

Go 默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不会影响到原来的变量,比如 Function(arg1)

几乎在任何情况下,传递指针(一个32位或者64位的值)的消耗都比传递副本来得少。

在函数调用时,像切片 (slice)、字典 (map)、接口 (interface)、通道 (channel) 这样的引用类型都是默认使用引用传递(即使没有显式的指出指针)。

有些函数只是完成一个任务,并没有返回值。我们仅仅是利用了这种函数的副作用 (side-effect),就像输出文本到终端,发送一个邮件或者是记录一个错误等。

但是绝大部分的函数还是带有返回值的。

类成员函数

package mainimport "fmt"type user struct {name     stringpassword string
}func (u *user) check2(password string) bool {return u.password == password
}func (u *user) reset(password string) { //从一个普通函数变成类成员函数u.password = password
}func main() {a := user{name: "wang", password: "1024"}a.reset("2048")fmt.Println(a.check2("2048"))
}

输出

true

改变外部变量

传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力,所以被修改的变量不再需要使用 return 返回。

如下的例子,reply 是一个指向 int 变量的指针,通过这个指针,我们在函数内修改了这个 int 变量的数值:

package mainimport ("fmt"
)// this function changes reply:
func Multiply(a, b int, reply *int) {*reply = a * b
}func main() {n := 0reply := &nMultiply(10, 5, reply)fmt.Println("Multiply:", *reply) // Multiply: 50
}

当需要在函数内改变一个占用内存比较大的变量时,性能优势就更加明显了。然而,如果不小心使用的话,传递一个指针很容易引发一些不确定的事,所以,我们要十分小心那些可以改变外部变量的函数,在必要时,需要添加注释以便其他人能够更加清楚的知道函数里面到底发生了什么。

变参函数

定义:如果一个函数最后的参数传递的是...type 类型,则可以处理变长的参数(长度可以为0)

这样的函数接受一个类似于slice的参数,再使用for loop

//函数声明
func myFunc(a, b, arg ...int) {}

如果参数为 slice类型,则可以通过 slice...来传递参数

package mainimport "fmt"func main() {x := min(1, 3, 2, 0)fmt.Printf("The minimum is: %d\n", x)slice := []int{7,9,3,5,1}x = min(slice...)fmt.Printf("The minimum in the slice is: %d", x)
}func min(s ...int) int {if len(s)==0 {return 0}min := s[0]for _, v := range s {if v < min {min = v}}return min
}

输出

The minimum is: 0
The minimum in the slice is: 1

一个接受变长参数的函数可以将这个参数作为其它函数的参数进行传递:

func F1(s ...string) {F2(s...)F3(s)
}func F2(s ...string) { }
func F3(s []string) { }

变长参数可以作为对应类型的 slice 进行二次传递。

但是如果变长参数的类型并不是都相同的呢?使用 5 个参数来进行传递并不是很明智的选择,有 2 种方案可以解决这个问题:

  1. 使用结构:

    定义一个结构类型,假设它叫 Options,用以存储所有可能的参数:

    type Options struct {par1 type1,par2 type2,...
    }
    

    函数 F1() 可以使用正常的参数 ab,以及一个没有任何初始化的 Options 结构: F1(a, b, Options {})。如果需要对选项进行初始化,则可以使用 F1(a, b, Options {par1:val1, par2:val2})

  2. 使用空接口:

    如果一个变长参数的类型没有被指定,则可以使用默认的空接口 interface{},这样就可以接受任何类型的参数。该方案不仅可以用于长度未知的参数,还可以用于任何不确定类型的参数。一般而言我们会使用一个 for-range 循环以及 switch 结构对每个参数的类型进行判断:

    func typecheck(..,..,values … interface{}) {for _, value := range values {switch v := value.(type) {case int:case float:case string:case bool:default:}}
    }
    

defer和追踪

说明

关键字defer允许推迟到函数的任意位置执行return语句之后的一刻,才执行某个语句或函数;一般用于释放某些已分配的资源

用法:类似于面向对象编程语言 Java 和 C# 的 finally 语句块,它一般用于释放某些已分配的资源

package main
import "fmt"func main() {function1()
}func function1() {fmt.Printf("In function1 at the top\n")defer function2() //被延后fmt.Printf("In function1 at the bottom!\n")
}func function2() {fmt.Printf("Function2: Deferred until the end of the calling function!")
}

输出

image-20231022200048723

使用 defer 的语句同样可以接受参数

//只是推迟输出,并未推迟执行
func a() {i := 0defer fmt.Println(i)i++fmt.Println(i)return
}
//最后输出为0

当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出):

//最后输出为 4 3 2 1 0
func f() {for i := 0; i < 5; i++ {defer fmt.Printf("%d ", i)}
}

一些常见操作

//关闭文件流
defer file.Close()
//解锁一个加锁资源
muu.Lock()
defer mu.Unlock()
//打印最终报告
printHeader()
defer printFooter()
//关闭数据库连接
defer disconnectFromDB()
实现
package mainimport "fmt"func main() {doDBOperations()
}func connectToDB() {fmt.Println("ok, connected to db")
}func disconnectFromDB() {fmt.Println("ok, disconnected from db")
}func doDBOperations() {connectToDB()fmt.Println("Defering the database disconnect.")defer disconnectFromDB() //function called here with deferfmt.Println("Doing some DB operations ...")fmt.Println("Oops! some crash or network error ...")fmt.Println("Returning from function here!")return //terminate the program// deferred function executed here just before actually returning, even if// there is a return or abnormal termination before
}

输出

image-20231022200619995

使用defer实现代码追踪

一个基础但十分实用的实现代码执行追踪的方案就是在进入和离开某个函数打印相关的消息,即可以提炼为下面两个函数:

func trace(s string) { fmt.Println("entering:", s) }
func untrace(s string) { fmt.Println("leaving:", s) }

以下代码展示了何时调用这两个函数:

package mainimport "fmt"func trace(s string) string {fmt.Println("entering:", s)return s
}func un(s string) {fmt.Println("leaving:", s)
}func a() {defer un(trace("a"))fmt.Println("in a")
}func b() {defer un(trace("b"))fmt.Println("in b")a()
}func main() {b()
}

输出

image-20231022200850456

记录函数的参数和返回值

package mainimport ("io""log"
)func func1(s string) (n int, err error) {defer func() {log.Printf("func1(%q) = %d, %v", s, n, err)}()return 7, io.EOF
}func main() {func1("Go")
}

输出

Output: 2011/10/04 10:46:11 func1("Go") = 7, EOF

常见的内置函数

Go 语言拥有一些不需要进行导入操作就可以使用的内置函数。它们有时可以针对不同的类型进行操作,例如:len()cap()append(),或必须用于系统级的操作,例如:panic()。因此,它们需要直接获得编译器的支持。

以下是一个简单的列表:

名称说明
close()用于管道通信
len()cap()len() 用于返回某个类型的长度或数量(字符串、数组、切片、map 和管道);cap() 是容量的意思,用于返回某个类型的最大容量(只能用于数组、切片和管道,不能用于 map
new()make()new()make() 均是用于分配内存:new() 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。它们的用法就像是函数,但是将类型作为参数:new(type)make(type)new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针(详见[第 10.1 节](file:///D:/self/资料/go/the-way-to-go/eBook/10.1.md))。它也可以被用于基本类型:v := new(int)make(T) 返回类型 T 的初始化之后的值,因此它比 new() 进行更多的工作(详见[第 7.2.3/4 节](file:///D:/self/资料/go/the-way-to-go/eBook/07.2.md)、[第 8.1.1 节](file:///D:/self/资料/go/the-way-to-go/eBook/08.1.md)和[第 14.2.1 节](file:///D:/self/资料/go/the-way-to-go/eBook/14.2.md))。new() 是一个函数,不要忘记它的括号
copy()append()用于复制和连接切片
panic()recover()两者均用于错误处理机制
print()println()底层打印函数(详见[第 4.2 节](file:///D:/self/资料/go/the-way-to-go/eBook/04.2.md)),在部署环境中建议使用 fmt
complex()real ()imag()用于创建和操作复数(详见[第 4.5.2.2 节](file:///D:/self/资料/go/the-way-to-go/eBook/04.5.md))

将函数作为参数

回调:函数可以作为其它函数的参数进行传递,然后在其它函数内调用执行

package mainimport ("fmt"
)func main() {callback(1, Add)
}func Add(a, b int) {fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b)
}func callback(y int, f func(int, int)) {f(y, 2) // this becomes Add(1, 2)
}

输出

The sum of 1 and 2 is: 3

将函数作为参数的最好的例子是函数 strings.IndexFunc()

该函数的签名是 func IndexFunc(s string, f func(c rune) bool) int,它的返回值是字符串 s 中第一个使函数 f(c) 返回 true 的 Unicode 字符的索引值。如果找不到,则返回 -1

例如 strings.IndexFunc(line, unicode.IsSpace) 就会返回 line 中第一个空白字符的索引值。当然,您也可以书写自己的函数:

func IsAscii(c int) bool {if c > 255 {return false}return true
}

闭包

不想给函数起名字则可以使用匿名函数

此函数不能独立存在,但可以被赋值于某个变量当中(保存函数的地址),再通过变量名对函数进行调用,也可以直接对匿名函数进行调用

//保存函数地址,并进行使用
fplus:=func(x,y int) int {return x +y }
fplus(3,4)
//直接调用
func(x,y int) int {return x + y} (3,4)
//计算1到100万整数的总和
func() {sum := 0for i := 1; i <= 1e6; i++ {sum += i}
}()

表示参数列表的第一对括号必须紧挨着关键字 func,因为匿名函数没有名称。花括号 {} 涵盖着函数体,最后的一对括号表示对该匿名函数的调用。

实例

package mainimport "fmt"func main() {f()
}
func f() {for i := 0; i < 4; i++ {g := func(i int) { fmt.Printf("%d ", i) }g(i)fmt.Printf(" - g is of type %T and has value %v\n", g, g)}
}

我们可以看到变量 g 代表的是 func(int),变量的值是一个内存地址

image-20231022204828753

关键字 defer 经常配合匿名函数使用,它可以用于改变函数的命名返回值。

匿名函数还可以配合 go 关键字来作为 goroutine 使用

匿名函数同样被称之为闭包(函数式语言的术语):它们被允许调用定义在其它环境下的变量。闭包可使得某个函数捕捉到一些外部状态,例如:函数被创建时的状态。另一种表示方式为:一个闭包继承了函数所声明时的作用域。这种状态(作用域内的变量)都被共享到闭包的环境中,因此这些变量可以在闭包中被操作,直到被销毁

闭包经常被用作包装函数:它们会预先定义好 1 个或多个参数以用于包装,详见下一节中的示例。另一个不错的应用就是使用闭包来完成更加简洁的错误检查

闭包将函数作为返回值

函数 Adder() 现在被赋值到变量 f 中(类型为 func(int) int

package mainimport "fmt"func main() {var f = Adder()fmt.Print(f(1), " - ")fmt.Print(f(20), " - ")fmt.Print(f(300))
}func Adder() func(int) int {var x intreturn func(delta int) int {x += deltareturn x}
}

输出

image-20231022205637298

在多次调用中,变量 x 的值是被保留的,即 0 + 1 = 1,然后 1 + 20 = 21,最后 21 + 300 = 321:闭包函数保存并积累其中的变量的值,不管外部函数退出与否,它都能够继续操作外部函数中的局部变量。

这些局部变量同样可以是参数

这样闭包函数就能够被应用到整个集合的元素上,并修改它们的值。然后这些变量就可以用于表示或计算全局或平均值。

一个返回值为另一个函数的函数可以被称之为工厂函数,这在您需要创建一系列相似的函数的时候非常有用:书写一个工厂函数而不是针对每种情况都书写一个函数。下面的函数演示了如何动态返回追加后缀的函数:

func MakeAddSuffix(suffix string) func(string) string {return func(name string) string {if !strings.HasSuffix(name, suffix) {return name + suffix}return name}
}

现在,我们可以生成如下函数:

addBmp := MakeAddSuffix(".bmp")
addJpeg := MakeAddSuffix(".jpeg")

然后调用它们:

addBmp("file") // returns: file.bmp
addJpeg("file") // returns: file.jpeg

可以返回其它函数的函数和接受其它函数作为参数的函数均被称之为高阶函数,是函数式语言的特点。我们已经在中得知函数也是一种值,因此很显然 Go 语言具有一些函数式语言的特性。闭包在 Go 语言中非常常见,常用于 goroutine 和管道操作。

我们将会看到 Go 语言中的函数在处理混合对象时的强大能力。

计算函数执行时间

有时候,能够知道一个计算执行消耗的时间是非常有意义的,尤其是在对比和基准测试中。最简单的一个办法就是在计算开始之前设置一个起始时间,再记录计算结束时的结束时间,最后计算它们的差值,就是这个计算所消耗的时间。想要实现这样的做法,可以使用 time 包中的 Now()Sub() 函数:

start := time.Now()
longCalculation()
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)

使用内存缓存来提升性能

类似于前缀和

内存缓存的技术在使用计算成本相对昂贵的函数时非常有用(不仅限于例子中的递归),譬如大量进行相同参数的运算。这种技术还可以应用于纯函数中,即相同输入必定获得相同输出的函数。

相关文章:

[Golang]多返回值函数、defer关键字、内置函数、变参函数、类成员函数、匿名函数

函数 文章目录 函数多返回值函数按值传递、按引用传递类成员函数改变外部变量变参函数defer和追踪说明一些常见操作实现 使用defer实现代码追踪记录函数的参数和返回值 常见的内置函数将函数作为参数闭包实例闭包将函数作为返回值 计算函数执行时间使用内存缓存来提升性能 参考…...

【剑指Offer】:删除链表中的倒数第N个节点(此题是LeetCode上面的)剑指Offer上面是链表中的倒数第K个节点

给定一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xff1a;…...

acwing第 126 场周赛 (扩展字符串)

5281. 扩展字符串 一、题目要求 某字符串序列 s0,s1,s2,… 的生成规律如下&#xff1a; s0 DKER EPH VOS GOLNJ ER RKH HNG OI RKH UOPMGB CPH VOS FSQVB DLMM VOS QETH SQBsnDKER EPH VOS GOLNJ UKLMH QHNGLNJ Asn−1AB CPH VOS FSQVB DLMM VOS QHNG Asn−1AB&#xff0c;其…...

Milvus 介绍

Milvus 介绍 Milvus 矢量数据库是什么&#xff1f;关键概念非结构化数据嵌入向量向量相似度搜索 为什么是 Milvus?支持哪些索引和指标&#xff1f;索引类型相似度指标(Similarity metrics) 应用示例Milvus 是如何设计的&#xff1f;开发者工具API访问Milvus 生态系统工具 本页…...

Linux绝对路径和相对路径

在 Linux 中&#xff0c;简单的理解一个文件的路径&#xff0c;指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置&#xff0c;那么它就可以找到这个文件。指明一个文件存放的位置&#xff0c;有 2 种方法&#xff0c;分别是使用绝对路径和相对路径。…...

Linux:firewalld防火墙-基础使用(2)

上一章 Linux&#xff1a;firewalld防火墙-介绍&#xff08;1&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/133960695?spm1001.2014.3001.5501 我使用的系统为centos7 firewalld启动停止等操作 systemctl start firewalld 开启防火墙 systemct…...

【每日一练】20231023

统计每个字符出现的次数相关问题 方法一&#xff1a;map的put方法遍历 public class Test {public static void main(String[] args) {StringBuilder sb new StringBuilder("");Random ran new Random();for(int i0;i<2000000;i) {sb.append((char) (a ran.n…...

【项目经理】工作流引擎

项目经理之 工作流引擎 一、业务系统管理目的维护信息 二、组织架构管理目的维护信息 三、角色矩阵管理目的维护信息 四、条件变量管理目的维护信息 五、流程模型管理目的维护信息 六、流程版本管理目的维护信息 七、流程监管控制目的维护信息 系列文章版本记录 一、业务系统管…...

025-第三代软件开发-实现需求长时间未操作返回登录界面

第三代软件开发-实现需求长时间未操作返回登录界面 文章目录 第三代软件开发-实现需求长时间未操作返回登录界面项目介绍实现需求长时间未操作返回登录界面实现思路用户操作监控QML 逻辑处理 关键字&#xff1a; Qt、 Qml、 QTimer、 timeout、 eventFilter 项目介绍 欢迎…...

驱动开发LED灯绑定设备文件

头文件 #ifndef __HEAD_H__ #define __HEAD_H__typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t;#define PHY_LED1_ADDR 0x50006000 #define PHY_LED2_ADDR 0x50007000 #defin…...

MySql 数据库基础概念,基本简单操作及数据类型介绍

文章目录 数据库基础为什么需要数据库&#xff1f;创建数据库mysql架构SQL语句分类编码集修改数据库属性数据库备份 表的基本操作存在时更新&#xff0c;不存在时插入 数据类型日期类型enum和set 数据库基础 以特定的格式保存文件&#xff0c;叫做数据库&#xff0c;这是狭义上…...

异步加载 JavaScript

目录 ​编辑 前言&#xff1a;异步加载 JavaScript 的重要性 详解&#xff1a;异步加载 JavaScript 的方法 使用 使用动态创建标签&#xff1a; 使用模块引入&#xff08;ES6模块&#xff09;&#xff1a; 解析&#xff1a;异步加载 JavaScript 的重要性和优势 实践和注…...

汽车屏类产品(四):仪表Cluster

###前言 仪表Cluster/仪表盘Dashboard,作为伴随汽车诞生就存在的一个主要零部件之一,从机械到电子到数字,可以说也是逐渐发展到现在的。 目前的主流框图如下,中间processor就是主控芯片,可能有buttons/switches,有display显示屏+backlight背光,有audio->speake…...

【GA-ELM】基于遗传算法优化极限学习机回归预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

DFT和ATE岗位前景薪资对比,手把手教你如何选择岗位?

ATE测试和DFT可测性设计&#xff0c;虽然二者都对芯片测试至关重要&#xff0c;但是两个岗位的区别还是很大的。 两个岗位应该如何做选择&#xff1f; 先讲产业环节 我们知道芯片设计、芯片制造、芯片封测每个环节都是大工程&#xff0c;且每个环节都关键且重要。测试是芯片诞…...

驱动day4作业

通过字符设备驱动的分步实现编写LED驱动&#xff0c;另外实现特备文件和设备的绑定 head.h #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }…...

【Oracle】VC6.0使用 odbc 访问 Oracle 存储过程

环境说明 系统环境 系统&#xff1a;Windows XP IDE&#xff1a; Microsoft Visual C 6.0 使用的对象 msado15.tlh _ConnectionPtr m_pConnection; HRESULT hr m_pConnection.CreateInstance(“ADODB.Connection”); _RecordsetPtr m_pRecordset; m_pRecordset.CreateInstan…...

QWidget快速美化-圆形蓝色单选框

将代码复制进QRadioButton的样式表 效果: 代码: QRadioButton{font:75 9pt "Arial";background:transparent;color:white;border:none; }QRadioButton:disabled{color:gray; }QRadioButton::indicator{width:12px;height:12px;border-radius:8px; }QRadioButton::i…...

adb 获取当前界面元素

adb配置正确&#xff0c;直接看6&#xff0c;pull的位置是你执行pull的目录下。 --------------------------------------------------------------------------------------------------------------------------------- 使用adb命令获取当前应用的元素需要先连接到手机或模…...

SpringSecurity源码学习四:会话管理

目录 1. 什么是会话管理2. springSecurity中的session管理怎么做的3. springSecurity源码中的session管理4. 代码示例5. 源码5.1 不同策略的含义 6. 集群模式session管理7. 总结 1. 什么是会话管理 会话管理是指在Java应用程序中管理用户会话状态的过程。在Spring框架中&#…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...