【Golang笔记02】函数、方法、泛型、接口学习笔记

Golang笔记02:函数、方法、泛型、接口学习笔记

一、进阶学习

1.1、函数

go中的函数使用func关键字进行定义,go程序的入口函数叫做:main,并且必须是属于main包里面。

1.1.1、定义函数
(1)普通函数

go中定义函数,需要使用func关键字,同时要指定函数名称,函数参数,函数返回值,函数体,这就是函数的五要素。语法格式:

func 函数名称(参数1,参数2,...)(返回值类型1,返回值类型2,...) {// 函数体
}// 当只有一个返回值类型的时候,可以省略括号(),直接写类型即可

go语言中,函数允许返回多个返回值,这个语法和其他的一些编程语言是有些区别的,比如:Java语言中,只允许一个函数返回一个返回值。go语言中,函数的特点:

  • 允许返回多个返回值。
  • 不允许函数重载。
// Method01 定义函数
func Method01() int {return 1 + 2
}// Method02 定义函数
func Method02(a int, b int) (int,int) {return a + b, a - b;
}

另外,如果函数参数的类型都是一致的,那么可以简写成下面这种方式:

// Method02 定义函数,参数类型相同,则可以简写
func Method02(a, b int) (int,int) {return a + b, a - b;
}
(2)函数字面量

函数字面量,是指将函数作为一个变量先定义出来,接着在需要使用的时候,通过func重新定义一个函数,然后函数字面量指向func函数。如下所示:

package mainimport "fmt"// 先定义一个函数字面量,函数体不定义
var method func(int, int) (int, int)// Method02 定义函数
func Method02(a int, b int) (int, int) {return a + b, a - b
}func main() {// 这里给函数字面量,指向具体的函数实现method := func(a int, b int) (int, int) {return a + b, a - b}// 调用函数add, sub := method(1, 2)fmt.Println(add, sub)
}
1.1.2、函数参数和返回值
(1)函数参数

go语言中的函数参数,如果是相同数据类型的,则可以统一定义类型,不需要每个参数都写出类型名称。格式:

func 函数名称(参数1,参数2,参数3 数据类型)(返回值1,返回值2...) {// 函数体
}

另外,go中函数参数的传递是值传递,也就是说,函数参数传递的时候,会拷贝实参的值。在函数体内修改函数参数的值,不会影响实参的值。

如果要定义可变参数,那么可以使用【...】符号,并且可变参数只能够在最后一个参数位置出现。

// 可变参数
func Method03(args ...int) {}
(2)函数返回值

go语言中,函数的返回值允许定义多个,当只有一个返回值,则可以不写括号,超过一个返回值的时候,则必须使用括号将所有返回值包裹起来。

// 只有一个返回值,可以省略返回值的括号
func demo() int {}
// 多返回值
func demo() (int,string){}

另外,go中函数返回值也可以定义名称,定义返回值名称之后,那么这个参数就可以在函数体中直接使用,并且通过return返回结果。

// Method02 定义函数
func Method02(a, b int) (add int,sub int) {// 可以使用函数返回值名称add = a + bsub = a - b// 定义了返回值名称,则return的时候,可以不写// 等价于 return add, subreturn//return add, sub
}
1.1.3、匿名函数

匿名函数,顾名思义,就是没有函数名称的函数。匿名函数一般在函数内部使用,语法格式:

package mainimport "fmt"func main() {// 定义匿名函数,并且调用函数ans := func(a, b int) int {ans := a + breturn ans}(1, 2)fmt.Println(ans)
}

匿名函数也可以作为一个函数的参数,例如:

package mainimport "fmt"// 定义函数,并且函数接受一个函数作为参数
func demo(a, b int, call func(int, int) int) int {return call(a, b)
}func main() {// 调用函数ans := demo(1, 2, func(a, b int) int {return a * b})fmt.Println(ans)// 调用函数ans2 := demo(1, 2, func(a, b int) int {return a + b})fmt.Println(ans2)
}
1.1.4、闭包

go语言中,函数有一个闭包的概念,闭包在一些编程语言中,又叫做:Lamda表达式。闭包,可以在内部函数中访问到外部函数的变量,即使外部函数已经执行完毕,内部函数仍然可以访问到外部的变量,这个过程就叫做:闭包。

  • 闭包=匿名函数+外部环境变量引用

下面给一个闭包的案例:

package mainimport "fmt"func main() {// 创建一个匿名函数,并且返回值是一个函数类型sum := func() func() int {a, b := 1, 1// 返回一个匿名函数,相当于回调函数,并且还修改外部函数 a、b 两个变量的值return func() int {// 引用外部函数的变量a, b = b, a+breturn a}}// 调用函数,并且返回值是个回调函数getSum := sum()for i := 0; i < 10; i++ {// 调用回调函数,由于闭包的特性,回调函数中仍然可以使用 sum() 函数中的变量 a、bfmt.Println(getSum())}
}

闭包结构中,外部函数执行结束之后,内部函数就相当于一个回调函数一样,仍然可以被继续调用,并且还可以使用外部函数中的变量。另外,多次调用外部函数获取到的回调函数,是互不影响的。

package mainimport "fmt"func demo() func() int {count := 0return func() int {count++return count}
}func main() {// 第一次调用外部函数f1 := demo()fmt.Println("调用f1()函数")fmt.Println(f1())fmt.Println(f1())fmt.Println(f1())// 第二次调用外部函数f2 := demo()fmt.Println("调用f2()函数")fmt.Println(f2())fmt.Println(f2())fmt.Println(f2())fmt.Println("再次调用 f1() 函数")// 再次调用 f1() 函数fmt.Println(f1())
}

上面案例中,就是演示的多次调用外部函数,获取到的回调函数之间是互不影响的。运行结果如下所示:

调用f1()函数
1
2
3
调用f2()函数
1
2
3
再次调用 f1() 函数
4

从上面的执行结果可以看到,f1()f2()之间的闭包结构是互不影响的。

1.1.5、延迟调用

go语言中,提供了一个defer关键字,可以用于声明函数的延迟调用功能。defer声明的延迟函数,会在外部函数执行完成之前,调用延迟函数,一般用于释放文件资源,关闭连接等操作。

注意:当一个函数中,存在多个defer定义的延迟函数,那么go会根据后进先出的规则,依次调用延迟函数。

怎么理解执行完成之前,才会调用defer延迟函数呢???

  • 当声明了defer函数的代码块内,执行到最后一行代码语句,后面已经没有可执行的语句的时候,但是函数还没有结束执行,只有遇到函数的最后一个右花括号【}】,才算执行结束。
  • 那么defer函数,就是在遇到右花括号【}】之前,会被调用的。
package mainimport "fmt"func deferDemo() {fmt.Println("3、执行延迟函数...")
}func main() {fmt.Println("1、执行main函数代码...")// 采用延迟函数的方式,调用方法,将在 main 函数执行完成之前,调用 deferDemo() 函数defer deferDemo()fmt.Println("2、执行main函数最后一句代码...")
}// 控制台输入结果
1、执行main函数代码...
2、执行main函数最后一句代码...
3、执行延迟函数...

从上面案例代码中,可以看到,虽然defer函数声明在中间位置,但是从控制台输出的结果来看,defer函数的内容确是最后打印出来的,这也就说明defer函数是最后执行的。

注意了,当存在多个defer延迟函数的时候,Go语言会按照后进先出的顺序,依次执行defer延迟函数。案例代码:

package mainimport "fmt"func demo01() {fmt.Println("调用demo01()函数...")
}
func demo02() {fmt.Println("调用demo02()函数...")
}
func demo03() {fmt.Println("调用demo03()函数...")
}func main() {fmt.Println("开始执行main函数...")// 定义延迟函数defer demo02()defer demo01()defer demo03()fmt.Println("main函数执行完成...")
}// 执行结果
开始执行main函数...
main函数执行完成...
调用demo03()函数...
调用demo01()函数...
调用demo02()函数...

1.2、方法

go语言中,既有函数,又有方法,在其他的语言中,一般情况下,函数和方法都是同一个概念,但是在go语言里面,两者是有点不同的。

go中的函数和方法,在定义形式上大体相同,只不过方法的定义,需要显示的声明方法的接收者,只有接收者才可以调用方法。方法定义格式:

// 自定义方法接收者的类型
type 接收者类型名称 接收者实际数据类型func (方法接收者名称 接收者类型名称) 方法名称(方法参数) 返回值类 {// 方法体
}

什么是方法接收者呢???要如何理解方法接收者这个概念???

  • 方法的接收者,可以理解成是方法的调用者,它是规定哪一种数据类型的对象,可以调用这个方法。
  • go语言中的方法接收者,就类似于java语言中的this关键字,例如:this.demo(),这个this就是方法的接收者,也可以理解成调用者。

方法的调用一般需要和自定义类型结合使用。

调用方法的语法格式:

变量名称 := 值
变量名称.方法名称()

方法的调用和函数的调用有点区别,函数是直接在代码中调用即可,不需要指定是由谁触发的调用。而方法,则需要指定具体的调用对象,是由哪个变量对象触发的方法调用。

package mainimport "fmt"// MyInt 先自定义一个类型
type MyInt intfunc (myInt MyInt) setValue(value int) {// 修改参数值myInt = MyInt(value)fmt.Println("方法中,修改的值=", myInt)
}func main() {var myInt MyInt = 1fmt.Println("修改之前的值=", myInt)// 调用方法myInt.setValue(2)fmt.Println("调用方法,修改之后的值=", myInt)
}// 执行结果
修改之前的值= 1
方法中,修改的值= 2
调用方法,修改之后的值= 1

从上面案例代码中,可以看到,我们虽然调用了setValue()方法去修改myInt的变量,但是方法执行完成之后,myInt的值仍然没有变化,这是为什么呢???

这就涉及到一个知识点了,方法的接收者分为两种情况:值接收者指针接收者

1.2.1、值接收者

go中方法的值接收者,是指方法接收者是通过值传递到方法里面的,传递的是形参,修改形参是不会影响到实际参数的。这和Java中的值传递的概念相同。

要想在方法里面,修改接收者的数据,那就需要通过指针接收者来实现。

1.2.2、指针接收者

方法指针接收者,这和Java中的引用传递的概念相同,在一个方法中,对引用传递的参数进行修改,实际上是对这个引用地址指向的数据进行了修改,会影响实际的参数。

go中的指针接收者作用就和Java引用传递作用相同,通过指针接收者修改数据,会将实际参数的值也一起更新了。

package mainimport "fmt"// MyInt 先自定义一个类型
type MyInt int// 方法接收者采用指针类型
func (myInt *MyInt) setValue(value int) {// 修改参数值*myInt = MyInt(value)fmt.Println("方法中,修改的值=", *myInt)
}func main() {var myInt MyInt = 1fmt.Println("修改之前的值=", myInt)// 调用方法,虽然 myInt 这里是值类型,但是 Go 会将其编译之后,就相当于是 (&myInt).setValue(2)myInt.setValue(2)fmt.Println("调用方法,修改之后的值=", myInt)
}// 执行结果
修改之前的值= 1
方法中,修改的值= 2
调用方法,修改之后的值= 2

1.3、接口介绍

Go中的接口分为两大类:基本接口通用接口

  • 基本接口:接口内部是一组方法的集合。
  • 通用接口:接口内部是一组类型的集合。

接口,是一组规范的集合,也就是说,接口只会规定实现功能的规范,但是具体的功能逻辑是怎么实现的,接口不负责,具体的功能实现交给具体的实现类。

Go中没有类与继承的概念,而是通过结构体来实现类的功能,那么在接口实现上,也是通过结构体来实现的。你可以怎么理解,创建一个struct结构体,就相当于是Java中创建了一个Class类。

1.3.1、基本接口

Go中定义接口需要使用interface关键字,这个关键字用于标识是接口类型。

(1)定义接口

基本接口的语法格式,如下所示:

// 基本接口的定义
type 接口名称 interface {// 定义方法方法名称(参数类型) 返回值类型方法名称(参数类型) 返回值类型方法名称(参数类型) 返回值类型
}

在定义基本接口的时候,接口内部只能够是一组方法的集合,不能存在其他的类型集合。针对接口中的方法,方法参数可以不用写参数名称,只需要指定类型即可,因为接口不具备实现逻辑,也就不会使用方法参数,所以写不写参数名称都没关系,但是类型是必须要规定的。

package mainimport "fmt"// BaseInterface 定义基本接口
type BaseInterface interface {// Say 定义两个方法Say(string) stringWalk()
}func main() {// 初始化接口var baseInterface BaseInterfacefmt.Println(baseInterface)
}

上面代码,就是定义了一个基本接口,并且在main函数中,初始化了接口,但是这个接口还没有具体实现,只是初始化了。

(2)接口实现

接口定义好了之后,那么要如何实现这个接口中的方法呢???Go语言中没有提供类似Java中的implements关键字,那么要怎么样才能实现接口呢???

Go语言中,接口的实现方式很简单,只需要一种类型(结构体或者自定义类型)将接口中的所有方法都实现了,那么我们就说,这个类型实现了某某接口。

package mainimport "fmt"// BaseInterface 定义基本接口
type BaseInterface interface {// Say 定义两个方法Say(string) stringWalk()
}// CustomType 定义类型,实现接口
type CustomType struct{}// Say CustomType 实现 BaseInterface 接口的方法
func (customType CustomType) Say(s string) string {fmt.Println("CustomType实现接口:saying..." + s)return s
}// Walk CustomType 实现 BaseInterface 接口的方法
func (customType CustomType) Walk() {fmt.Println("CustomType实现接口:walking...")
}func main() {
}

上面案例代码中,自定义了CustomType结构体类型,然后这个结构体定义了两个方法,方法和接口中定义的方法名称一致,那么这种情况下,CustomType类型就是实现了BaseInterface接口了。

Go语言中接口的实现都是隐式的,不像Java中的接口实现那样,还需要使用implements关键字才能够实现接口。

(3)使用接口

实现接口之后,就需要在相应的地方,使用接口实现来完成业务功能啦。使用接口很简单,其实就是通过接口的实现类,调用对应的接口方法即可。

package mainimport "fmt"// BaseInterface 定义基本接口
type BaseInterface interface {// Say 定义两个方法Say(string) stringWalk()
}// CustomType 定义类型,实现接口
type CustomType struct{}// Say CustomType 实现 BaseInterface 接口的方法
func (customType CustomType) Say(s string) string {fmt.Println("CustomType实现接口:saying..." + s)return s
}// Walk CustomType 实现 BaseInterface 接口的方法
func (customType CustomType) Walk() {fmt.Println("CustomType实现接口:walking...")
}func main() {// 定义接口实现类customType := CustomType{}// 调用接口方法say := customType.Say("Hello World")fmt.Println("返回值:" + say)customType.Walk()
}

从上面案例代码中,可以发现一个问题,在使用接口的时候,我们的代码里面没有直接出现BaseInterface这个接口,而是定义了一个CustomType结构体的变量,然后通过结构体变量去调用了结构体实现的SayWalk两个方法。

这是因为Go语言中,某个类型(结构体或者自定义类型)实现某个接口之后,对应的类型就已经满足接口中定义的方法规范。

(4)空接口

Go中提供了一个空接口,空接口就是接口中没有定义任何的方法,里面是空的。空接口相当于Java中的Object对象,是所有类型的父类型,Go中的空接口就是所有类型的父类型。

// 定义空接口变量
interfaceVar interface{}

空接口可以作为一个方法的参数,这个参数叫做:空接口变量。空接口变量可以接收任意的数据类型,从而就可以实现同一个方法可以处理多种类型的参数。

package mainimport "fmt"func demo(interfaceVar interface{}) {switch v := interfaceVar.(type) {case int:fmt.Println("int 类型", v)case string:fmt.Println("string 类型", v)default:fmt.Println("都不满足的类型")}
}func main() {// 定义int类型myInt := 10demo(myInt)// 定义string类型myStr := "hello world"demo(myStr)
}
(5)类型切换和断言

Go语言中,提供了一种特殊的语法,叫做:类型切换类型断言。语法格式:

// 类型切换和类型断言
v := interfaceVar.(T)// interfaceVar 表示接口变量
// T 表示数据类型
// v 是一个变量,具体来说是一个动态类型变量,它的类型会根据 interfaceVar.(T) 检测出来的类型变化
// 当 v 的类型和 case 类型匹配时候,那么 v 变量就会被赋值对应类型的数据值

上面表达式用在switch结构里面,能够动态的检查接口变量interfaceVar的具体类型,并且将变量的值赋值给变量v

类型切换和类型断言的代码执行规则,我理解大概是这样的:

1、首先进行类型切换,通过 interfaceVar.(T),获取到具体的类型
2、将获取到具体类型赋值给 v 变量
3、v 变量的类型再和 case 中的类型进行匹配
4、如果 v 能够匹配上 case 的类型,则将对应类型的值赋值给 v 变量

案例代码:

package mainimport "fmt"func demo(interfaceVar interface{}) {switch v := interfaceVar.(type) {case int:fmt.Println("int 类型", v)case string:fmt.Println("string 类型", v)default:fmt.Println("都不满足的类型")}
}func main() {// 定义int类型myInt := 10demo(myInt)// 定义string类型myStr := "hello world"demo(myStr)// 定义 float 类型myFloat := 3.14demo(myFloat)
}
1.3.2、通用接口

go中的通用接口,需要和泛型结合使用,这样才可以定义一个通用的接口,让所有的数据类型都适用,这就是通用接口。后续介绍泛型时候,在一起介绍通用接口。

1.4、泛型

Go语言在1.18版本中引入泛型的概念。泛型定义的语法格式如下所示:

// 泛型定义
[泛型参数 约束类型1 | 约束类型2...]// 举个例子:
func sum[T int | float32](a,b T) T {// 方法体
}

类型约束是指:当前泛型可以接收哪些数据类型,如果不是这里面的类型,那么就无法使用对应的方法、函数之类的。

上面就是定义泛型时候的语法格式,那要如何使用呢???

在使用泛型的时候,可以有两种方式:

  • 第一种方式:使用时候指定具体的数据类型。
  • 第二种方式:不指定类型,让编译期自动推断类型。
package mainimport "fmt"// 定义泛型方法
func sum[T int | float32](a, b T) T {return a + b
}func main() {// 计算 int 类型ans := sum(1, 2)fmt.Println(ans)// 主动指定类型ans2 := sum[float32](3.14, 2.86)fmt.Println(ans2)
}

泛型结构的使用注意事项:

  • 泛型不能用在基本类型上。
  • 泛型不能进行类型断言。
  • 匿名结构中,不允许使用泛型。
  • 匿名函数不支持自定义泛型。
  • 方法不能使用泛型。

为什么方法上面不能使用泛型呢???

我是这么理解的,因为Go中不允许方法重载,所以如果方法上面使用了泛型,那不就是相当于Go中会存在两个相同名称的方法了吗?这就和Go中不允许方法重载的定义相违背了,所以也就不允许方法使用泛型了。

1.5、类型

Go语言中的类型,是一种静态强类型,什么是静态呢???

静态强类型

静态是指:Go中的数据类型一旦定义出来之后,在编译期期间就已经确定了,后续运行程序的时候,就不能够改变类型了。

强类型是指:当我们程序员在写代码的时候,如果改变了数据类型,那么编译期就会马上提示程序员,语法错了,不能修改类型。

var a int = 1
// 编译不通过,因为前后类型不一致
a = "2"

类型后置

Go语言中,所有的数据类型都是写在名称后面的,这是因为写在变量名称后面,能够让程序的可读性更强,类型太多的时候不至于看着混乱。

var 变量名称 数据类型

类型声明

Go语言中,使用type关键字声明类型,自定义类型也是使用type关键字定义的。

// 声明类型
type 类型名称 数据类型

类型转换

Go语言中,没有类型Java语言中的隐式类型转换的功能,Go语言只有显式类型转换,也就是说,必须让程序员在代码中主动的进行类型转换。

package mainimport "fmt"func main() {var f float64 = 3.14// 强制类型转换var f2 int = int(f)fmt.Println(f2)
}

以上就是Go语言中函数、方法、泛型、接口相关的学习笔记内容。

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

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

相关文章

LLM笔记(九)KV缓存调研

KV 缓存 (Key-Value Cache) 技术详解 KV 缓存&#xff08;Key-Value Cache&#xff09;是在 Transformer 模型&#xff08;尤其是 Decoder-Only 架构或 Encoder-Decoder 架构的 Decoder 部分&#xff09;进行自回归 (auto-regressive) 推理生成序列时&#xff0c;一种至关重要…

【Boost搜索引擎】构建Boost站内搜索引擎实践

目录 1. 搜索引擎的相关宏观原理 2. 正排索引 vs 倒排索引 - 搜索引擎具体原理 3. 编写数据去标签与数据清洗的模块 Parser 去标签 编写parser 用boost枚举文件名 解析html 提取title ​编辑 去标签 构建URL 将解析内容写入文件中 4. 编写建立索引的模块 Index 建…

LeetCode 热题 100 1.两数之和

目录 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 思路&#xff1a; 思路一暴力遍历&#xff1a; 代码&#xff1a; 暴力遍历Java代码&#xff1a; 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 1. 两数之和 - 力扣&#xff08;LeetC…

基于LSTM-GARCH混合模型的黄金价格波动率预测:信用降级事件冲击评估

摘要&#xff1a;本文构建多维度量化分析框架&#xff0c;对近期黄金市场波动进行技术解构。通过主权信用评级调整、地缘风险及宏观经济数据等公开信息源&#xff0c;运用统计学习模型解析市场驱动因素&#xff0c;避免主观预判。文中所有技术分析均基于历史数据回测&#xff0…

分布式与集群:概念、区别与协同

分布式与集群:概念、区别与协同 在分布式系统与云计算领域,分布式(Distributed)和集群(Cluster)是两个高频出现的核心概念。它们常被混淆,但本质上属于不同维度的设计思想。本文将从定义、分类、实际应用及协同关系四个层面,结合 Dubbo、Git、Hadoop 等典型案例,系统…

Prometheus实战教程:k8s平台-Mysql监控案例

配置文件优化后的 Prometheus 自动发现 MySQL 实例的完整 YAML 文件。该配置包括&#xff1a; MySQL Exporter 部署&#xff1a;使用 ConfigMap 提供 MySQL 连接信息。Prometheus 自动发现&#xff1a;通过 Kubernetes 服务发现自动抓取 MySQL 实例。 1、mysql 配置文件 &…

基于区块链技术的智能汽车诊断与性能分析

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 钝感力的“钝”&#xff0c;不是木讷、迟钝&#xff0c;而是直面困境的韧劲和耐力&#xff0c;是面对外界…

文字溢出省略号显示

一、 单行文字溢出、省略号显示 二、 多行文字溢出&#xff0c;省略号显示 有较大的兼容性问题&#xff0c;适用于Webkit为内核的浏览器软件&#xff0c;或者移动端的&#xff08;大部分也是webkit&#xff09; 此效果建议后端人员开发 三、图片底侧空白缝隙的修复技巧&#…

JavaScript 中使用 Elasticsearch 的正确方式,第一部分

作者&#xff1a;来自 Elastic Jeffrey Rengifo 讲解如何用 JavaScript 创建一个可用于生产环境的 Elasticsearch 后端。 想获得 Elastic 认证&#xff1f;看看下一期 Elasticsearch 工程师培训什么时候开始吧&#xff01; Elasticsearch 拥有大量新功能&#xff0c;能帮助你…

RAG-MCP:突破大模型工具调用瓶颈,告别Prompt膨胀

大语言模型&#xff08;LLM&#xff09;的浪潮正席卷全球&#xff0c;其强大的自然语言理解、生成和推理能力&#xff0c;为各行各业带来了前所未有的机遇。然而&#xff0c;正如我们在之前的探讨中多次提及&#xff0c;LLM并非万能。它们受限于训练数据的时效性和范围&#xf…

鸿蒙OSUniApp制作一个小巧的图片浏览器#三方框架 #Uniapp

利用UniApp制作一个小巧的图片浏览器 最近接了个需求&#xff0c;要求做一个轻量级的图片浏览工具&#xff0c;考虑到多端适配的问题&#xff0c;果断选择了UniApp作为开发框架。本文记录了我从0到1的开发过程&#xff0c;希望能给有类似需求的小伙伴一些参考。 前言 移动互联…

Python爬虫实战:获取taobao网最新rtx5060ti显卡销量数据并分析,为消费者做参考

一、系统定义与技术架构 1.1 系统定义 本系统是基于 Python 开发的电商数据采集与分析工具,旨在通过模拟用户行为实现淘宝平台 50 系列显卡(以 RTX 5060 Ti 为例)销售数据的自动化获取、清洗、分析及可视化。核心功能包括: 自动登录:通过 Selenium 模拟浏览器操作完成账…

OCframework编译Swift

建一个OC的framework&#xff1a; 需要对外暴露的OC文件&#xff0c;需要放到OC的.h文件中 framework中&#xff0c;OC类&#xff0c;调用framework中的Swift类&#xff1a; #import "WowAudioFocus/WowAudioFocus-Swift.h" //02 #import "{工程名}/{工程…

每日算法 -【Swift 算法】Two Sum 问题:从暴力解法到最优解法的演进

【Swift 算法】Two Sum 问题&#xff1a;从暴力解法到最优解法的演进 本文通过“Two Sum”问题&#xff0c;带你了解如何从最直观的暴力解法&#xff0c;逐步优化到高效的哈希表解法&#xff0c;并对两者进行对比&#xff0c;适合算法入门和面试准备。 &#x1f4a1; 问题描述 …

【保姆级】Nginx简介以及安装

Nginx简介 ​ Nginx是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;第一个公开版本0.1.0发布于20…

C++(25): 标准库 <deque>

目录 1、 核心概念 2. 基本语法 3. 特点 4. 特有成员函数 5. 内存与性能 6. 示例代码 7. 成员函数列表 8. 使用场景 9. 注意事项 1、 核心概念 双端队列(Double-Ended Queue,deque) 是一种允许在队列头部和尾部高效插入和删除元素的线性数据结构,同时支持随机访问。…

软件设计师关系代数和元组演算(关联、笛卡尔积、除、映射、分段等问题)考点分析——求三连

一、考点分值占比与趋势分析 综合知识历年统计表 年份考题数量分值分值占比考察重点2018334%自然连接、投影、选择2019222.67%笛卡尔积、条件筛选2020111.33%属性列计算2021334%关系运算综合应用2022222.67%元组演算表达式2023222.67%差运算、连接类型2024111.33%除法运算应用…

卸载云枢(MacOS 版)

删除 APP 和相关文件 sudo chflags -R noschg /Applications/Yunshu.app 2>/dev/null sudo rm -rf /Applications/Yunshu.app sudo rm -rf /Library/Application\ Support/EagleCloud sudo rm -rf /Library/LaunchAgents/com.eagleyun.endpoint.agent.plist sudo rm -rf /L…

在 Ubuntu 20.04 中使用 init.d 或者systemd实现开机自动执行脚本

Ubuntu 20 默认使用的是 systemd 系统管理器&#xff0c;但传统的 SysV Init&#xff08;/etc/init.d/&#xff09;脚本依然兼容并可用。本文将介绍如何通过 init.d 写脚本来在开机时自动设置某个 GPIO&#xff08;如 GPIO407&#xff09;为高电平&#xff0c;适用于嵌入式系统…

苹果的人工智能领域慢热

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…