Go学习第五章——函数与包

news2024/11/18 3:40:08

Go学习第五章——函数与包

      • 1 函数
        • 1.1 基本语法
        • 1.2 函数多返回值
        • 1.3 函数的可见性和包级函数
        • 1.4 函数调用机制底层原理
        • 1.5 值类型和引用类型
        • 1.6 注意事项和细节
        • 1.7 逃逸机制(补,可不看)
      • 2 包
        • 2.1 快速入门
        • 2.2 包的使用细节
      • 3 函数详细讲解
        • 3.1 递归调用
        • 3.2 可变函数参数
        • 3.3 init 函数
        • 3.4 匿名函数
        • 3.5 闭包
        • 3.6 函数作为参数和返回值
        • 3.7 defer函数
        • 3.8 作为结构体的方法
      • 4 变量的作用域

1 函数

函数是一段可以重复执行的代码块,通过函数可以将代码模块化,提高代码的可读性和可维护性。

要定义函数,需要指定函数的名称、参数和返回值(如果有的话)。

1.1 基本语法

基本语法

func   函数名(形参列表)(返回值类型列表){
	执行语句..
	return + 返回值列表
}

下面是一个简单的示例,展示了如何定义和调用一个简单的函数:

package main

import "fmt"

// 定义一个名为greeting的函数,它接收一个字符串参数name并没有返回值
func greeting(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    // 调用greeting函数,传入一个名字作为参数
    greeting("Alice")
}

运行上面的代码,输出结果为:

Hello, Alice!
1.2 函数多返回值

在 Go 语言中,函数可以返回多个值。这在某些情况下很有用,例如一个函数需要返回多个计算结果,或者需要返回一个值和一个错误状态。

下面是一个示例,展示了如何定义和使用返回多个值的函数:

package main

import "fmt"

// 定义一个名为divide的函数,它接收两个整数参数,并返回一个商和余数
func divide(a, b int) (int, int) {
    quotient := a / b
    remainder := a % b
    return quotient, remainder
}

func main() {
    // 调用divide函数,并接收两个返回值
    q, r := divide(10, 3)
    fmt.Printf("商:%d,余数:%d\n", q, r)
}

运行上面的代码,输出结果为:

商:3,余数:1

通过返回多个值,函数的调用方可以方便地获得函数计算的多个结果。

1.3 函数的可见性和包级函数

在 Go 语言中,函数和变量的可见性是由它们的命名规则决定的。一个函数或变量是否对其他代码可见,取决于它们的名称是否以大写字母开头

如果一个函数或变量的名称以大写字母开头,则它对其他代码可见;如果名称以小写字母开头,则它只对同一个包内的代码可见。

下面是一个示例,展示了可见性的规则:

package main

import "fmt"

// 可以被其他代码访问
func PublicFunc() {
    fmt.Println("公有函数")
}

// 只能在当前包内访问
func privateFunc() {
    fmt.Println("私有函数")
}

func main() {
    PublicFunc()
    privateFunc() // 错误:无法访问私有函数
}

在这个示例中,我们定义了一个名为 PublicFunc 的公有函数,以及一个名为 privateFunc 的私有函数。在 main 函数中,我们可以正常调用 PublicFunc,但无法调用 privateFunc

按照这个规则,我们可以将一些公共的、被其他代码调用的函数定义为包级函数,并将一些内部函数定义为私有函数。这有助于将代码逻辑与实现细节隔离,并提高代码的封装性。

1.4 函数调用机制底层原理
  1. 执行n1 := 10,会生成一个存储这个值的区域,这里只是抽象为有这么一个main栈区,实际上不是这样命名,是使用寄存器和栈帧来实现,具体不讲解
  2. 因为是栈的方式,后进先出,所以这里调用函数后占用的数据,也会被优先回收掉。

在这里插入图片描述

函数调用是计算机程序中的一个重要概念,它用于在程序执行过程中跳转到函数代码的起始位置,并在函数执行完毕后返回到原来的位置。函数调用的底层实现涉及到栈的分配、参数传递和返回值处理等过程。

  1. 栈空间的分配:每个线程都会有自己的栈空间,用于存储函数的局部变量、函数参数和返回值。函数调用时,会给调用栈分配一块空间来存储函数执行过程中所需的数据。栈的分配是一个后进先出(LIFO)的过程,即新的函数调用会在栈的顶部分配空间

  2. 参数传递:函数调用需要将参数传递给被调用的函数。参数的传递方式一般分为两种:值传递和引用传递

  • 在值传递中,参数的值会被复制到被调用函数的栈帧中,由于是复制操作,被调函数的修改不会影响到调用函数。

  • 在引用传递中,函数参数是一个指针,传递的是变量在内存中的地址,被调用函数可以通过指针来访问和修改原始数据。

  1. 函数调用过程:当一个函数需要调用另一个函数时,会先将当前函数的执行状态压入栈中,包括返回地址、参数、局部变量等信息。然后跳转到被调用函数的起始位置,执行被调用函数的代码。在被调用函数执行结束后,会将返回值返回给调用函数,在栈中恢复调用函数的执行状态,包括返回地址和栈帧等信息,然后继续执行。

  2. 返回值处理:函数执行完毕后,需要将返回值返回给调用函数。返回值的处理方式和参数传递类似,可以使用值传递或者引用传递。在实际的底层实现中,一般通过寄存器或者栈帧来传递和存储返回值。

总结起来,函数调用的底层实现主要涉及栈空间的分配与释放、参数传递和返回值处理等过程。这些过程是通过寄存器和栈帧来实现的,不同的编程语言和编译器可能会有一些细节上的差异,但基本思想是相通的。

1.5 值类型和引用类型

前面使用的值传输,所以会发现函数并没有修改值,只是修改函数本身的栈空间里的变量值,当然还有相对应,可以直接通过引用类型传递,修改对应的值。

使用传输地址,也就是引用传递的方式,让函数直接修改地址值。

import "fmt"

func add1(num int) {
	num = num + 1
	fmt.Println("在add1函数里,num=", num)
}

func add2(num *int) {
	*num = *num + 1
	fmt.Println("在add2函数里,num=", *num)
}

func main() {
	var num int = 2
	add1(num)
	fmt.Println("在main函数里,第一次,num=", num)
	add2(&num)
	fmt.Println("在main函数里,第二次,num=", num)
}

输出结果:

在add1函数里,num= 3
在main函数里,第一次,num= 2
在add2函数里,num= 3
在main函数里,第二次,num= 3
1.6 注意事项和细节
  1. golang不支持重载(通过其他方式实现)
  2. 在Go中,函数也是一种数据类型,可以赋值给一个变量,则该变量就是一个函数类型的变量了。通过该变量可以对函数调用。
  3. 函数既然是一种数据类型,因此在Go中,函数可以作为形参,并且调用。
  4. 为了简化数据类型定义,Go支持自定义数据类型
  • 基本语法:type 自定义数据类型名 数据类型 // 理解:相当于一个别名
  • 案例:type myInt int // 这是myInt就等价int来使用了
  • 案例:type mySum func(int, int) int // 这是mySum就等价一个函数类型func (int, int) int
import "fmt"

type myFunType func(int, int) int

func myFun(funvar myFunType, num1 int, num2 int) int {
	return funvar(num1, num2)
}

func main() {
	type myInt int

	var num1 myInt = 40
	// num2 := int(num1) // 报错,因为myInt本质是,不是一个数据类型
	fmt.Println("num1=", num1)

	res := myFun(func(i1 int, i2 int) int { // 这里用到了匿名函数,可以去看看后面所说的定义
		return i1 + i2
	}, 500, 600)
	fmt.Println("res=", res)
}

输出:

num1= 40
res= 1100
  1. 支持对函数返回值命名

cal1和cal2的函数是一样的,只是cal2里对返回值命名,这样就可以不用考虑顺序,因为如果是cal1的方式,return的值需要考虑跟返回值类型的顺序一样。

import (
	"fmt"
	"strconv"
)

func cal1(n1 int, n2 int) (int, string) {
	sum := n1 + n2
	sub := strconv.FormatInt(int64(n1-n2), 10)
	return sum, sub
}

func cal2(n1 int, n2 int) (sum int, sub string) {
	sub = strconv.FormatInt(int64(n1-n2), 10)
	sum = n1 + n2
	return
}

func main() {
	sum1, sub1 := cal1(2, 2)
	sum2, sub2 := cal2(2, 2)

	fmt.Printf("cal1的返回值:%v, %v \n", sum1, sub1)
	fmt.Printf("cal2的返回值:%v, %v \n", sum2, sub2)
}

输出结果:

cal1的返回值:4, 0
cal2的返回值:4, 0
  1. 使用_标识符,忽略返回值
import "fmt"

func cal(n1 int, n2 int) (sum int, sub int) {
	sum = n1 + n2
	sub = n1 - n2
	return
}

func main() {
	res1, _ := cal(10, 20)
	fmt.Printf("res1 = %d", res1)
}

输出:res1 = 30

1.7 逃逸机制(补,可不看)

逃逸分析是编译器的一种静态分析技术,用于分析程序中的变量是否会逃逸到堆上分配内存。逃逸指的是当一个变量在函数内部分配内存,并且在函数外部被引用时,该变量就会逃逸到堆上。

逃逸分析的作用是优化内存分配和回收,将一部分变量从堆上分配转移到栈上分配,减少堆的压力和垃圾回收的负担。逃逸分析可以减少内存分配的次数,避免频繁的系统调用和锁竞争,提高程序的性能和并发能力。

逃逸分析的实现原理可以分为以下几个步骤:

  1. 内联优化:逃逸分析通常是在函数级别上进行的,首先编译器会尝试内联函数。内联优化是将函数的代码插入到调用它的函数中,减少函数调用的开销。内联优化会扩展函数的作用域,使函数内部的变量和参数可以直接访问。这样,一些局部变量就可以在栈上分配,而不是在堆上分配。

  2. 变量分析:逃逸分析会对函数的变量进行分析,判断变量是否逃逸。如果一个变量逃逸,编译器会将其分配在堆上;如果一个变量不逃逸,则可以将其分配在栈上。变量的逃逸分析包括以下情况的判断:

    • 变量是否在函数返回后继续存在;
    • 变量是否被存储到全局变量中,以供其他函数使用;
    • 变量是否被闭包函数引用。
  3. 逃逸分析结果的使用:逃逸分析的结果会被编译器用于指导内存分配器进行内存分配。根据逃逸分析的结果,编译器可以决定将变量分配在栈上还是堆上。对于不逃逸的变量,编译器可以直接在栈上分配内存,避免了堆分配和垃圾回收的开销。

总结起来,逃逸分析是一种优化技术,它使用静态分析的方法判断变量是否会逃逸到堆上分配内存。逃逸分析的作用是减少堆的压力和垃圾回收的负担,提高程序的性能和并发能力。逃逸分析的实现原理包括内联优化、变量分析和逃逸分析结果的使用。

2 包

go的每一个文件都是属于一个包,也就是说go是以包的形式来管理文件和项目目录结构。

2.1 快速入门

包的三大作用:

  1. 区分相同名字的很熟、变量等标识符
  2. 当程序文件很多时,可以很好的管理项目
  3. 控制函数、变量等访问范围,即作用域

首先创建不同文件夹下面的包,再编写好对应的函数,然后import导入,最后调用!

在这里插入图片描述

2.2 包的使用细节
  1. 在给一个文件夹打包时,该包对应一个文件夹,比如这里的是utils文件夹对应的包名就是utils,文件的包名通常和文件所在的文件夹名一致,一般为小写字母。

  2. 当包名过长时,可以给包名取别名,取完之后,之前的就不能用了

在import时,在前面写的代码,就是别名。例如:这里把utils改成util。

package main

import (
	util "GoStudy_Day1/Day03/model/utils"
	"fmt"
)

func main() {
	var num int = 2
	nums := util.Cal(num)
	fmt.Printf("%v 的平方等于:%v \n", num, nums)
}
  1. 编译一个可执行程序文件,就需要将这个包声明为main,然后实际开发的时候,都是编译成exe文件再运行。

编译可以指定名字和目录,比如:放在bin目录下:go build -o bin/my.exe go_code/project/main

3 函数详细讲解

3.1 递归调用

在函数里,又调用了本身,也就是自己

下面是一个案例和底层栈空间的调用情况

在这里插入图片描述

注意细节:

  1. 执行一个函数时,就会串接一个新的受保护的独立空间(新函数栈,如图所示)
  2. 函数的局部变量是独立的,不会相互影响
  3. 递归必须向退出递归的条件逼近,否则就是无限递归,很容易栈溢出崩溃,实际开发不怎么用
  4. 当一个函数执行完毕或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时函数执行完毕就销毁。
3.2 可变函数参数

可变参数函数是指可以接收不定数量参数的函数,这些参数被看作是一个切片。

Go 语言中的可变参数函数使用 ... 表示。

下面是一个示例,展示了如何定义和调用可变参数函数:

package main

import "fmt"

// 定义一个名为sum的函数,它接收任意数量的整数参数,并返回它们的总和
func sum(nums ...int) int {
    total := 0
    for _, num := range nums {
        total += num
    }
    return total
}

func main() {
    // 调用sum函数,传入多个整数参数
    fmt.Println("总和:", sum(1, 2, 3, 4, 5))
    fmt.Println("总和:", sum(10, 20, 30))
}

运行上面的代码,输出结果为:

总和: 15
总和: 60

在这个示例中,我们定义了一个名为 sum 的函数,它可以接收任意数量的整数参数,并返回它们的总和。在 main 函数中,我们调用了 sum 函数两次,并传递了不同数量的参数。

通过使用可变参数,我们可以简化函数的调用,使之更加灵活。

3.3 init 函数

基本介绍:

每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用,也就是说init会在main函数前被调用。

案例说明:

import "fmt"

func init() {
	fmt.Println("main init...")
}

func main() {
	fmt.Println("main...")
}

输出结果:

main init...
main... 

细节讨论:

  1. 如果一个文件同时包含全局变量定义,init函数和main函数,则执行的流程是变量定义->init函数->main函数
  2. init函数最主要的作用,就是完成一些初始化的工作,比如下面的案例:

utils包:

package utils

var Name string
var Age int

func init() {
    Name = "Tom"
    Age = 100
}

main包

import (
	"GoStudy_Day1/Day03/model/utils"
	"fmt"
)

func main() {
	fmt.Printf("Name = %v, Age = %v", utils.Name, utils.Age)
}

输出结果:Name = Tom, Age = 100

从过程可以看出,有点像Java定义成员变量,并且给一个默认值的感觉

3.4 匿名函数

匿名函数是一种特殊的函数,它没有函数名,可以直接在其他函数中定义和使用。匿名函数在需要临时定义一段代码,并且这段代码不需要复用时很有用。

下面是示例,展示了如何定义和调用匿名函数:

实例一:

package main

import "fmt"

func main() {
    // 在main函数内定义一个匿名函数,并立即调用它
    func() {
        fmt.Println("这是一个匿名函数!")
    }()

    // 将匿名函数赋值给变量,然后进行调用
    greeting := func(name string) {
        fmt.Printf("Hello, %s!\n", name)
    }
    greeting("Alice")
}

运行上面的代码,输出结果为:

这是一个匿名函数!
Hello, Alice!

实例二:将匿名函数赋给a变量

func main() {
    a := func(n1 int, n2 int) int {
       return n1 - n2
    }

    res2 := a(10, 10)
    fmt.Println("res2=", res2)
}

输出结果:res2= 0

实例三:匿名函数赋值给全局变量,那么就成为一个全局匿名函数

这里不写了,跟上面雷同~~~

匿名函数可以用于需要临时定义一段代码的场景,例如在并发编程中,可以将匿名函数传递给协程进行并发执行。

3.5 闭包

闭包是指一个函数捕获并保存了其自身外部作用域的变量的引用。

简单来说,闭包就是一个函数以及它所引用的变量的组合体。

下面是一个示例,展示了如何使用闭包:

package main

import "fmt"

// 定义一个名为counter的函数,返回一个匿名函数
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    // 创建一个计数器实例
    c := counter()

    // 使用闭包进行计数
    fmt.Println(c()) // 输出:1
    fmt.Println(c()) // 输出:2
    fmt.Println(c()) // 输出:3
}

运行上面的代码,输出结果为:

1
2
3

在这个示例中,我们定义了一个 counter 函数,它返回一个匿名函数。在匿名函数内部,我们定义了一个变量 count,然后在每次调用匿名函数时更新这个变量,并返回它的值。

最佳实践

假设传入一个文件名,设置一个变量作为文件名的后缀,如果这个文件名没有指定的后缀,则自动给这个文件名添加后缀,如果有的话,直接输出。

这里需要使用HasSuffix函数,表示查找该该string有没有指定的后缀

func makeSuffix(suffix string) func(string) string {
	return func(name string) string {
		// 如果 name 没有指定后缀,则加上,否则就返回原来的名字
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}

		return name
	}
}

func main() {
	f := makeSuffix(".jpg")
	fmt.Println("文件名处理后=", f("winter"))
	fmt.Println("文件名处理后=", f("winter.jpg"))
}

输出结果:

文件名处理后= winter.jpg
文件名处理后= winter.jpg

虽然也可以用普通函数实现,但是过程太过复杂,所以不用。

通过闭包,我们可以创建一个状态被隐藏的函数,这个函数可以持续地访问和修改它所引用的变量。

ps:闭包还能通过这方式实现协程之间的数据传递,不过需要避免变量共享问题。(以后再讲~~)

3.6 函数作为参数和返回值

在 Go 语言中,函数可以作为参数传递给其他函数,也可以作为函数的返回值。这种能力使得代码更加灵活,可以根据需要将函数与其他函数进行组合。

下面是一个示例,展示了如何将函数作为参数和返回值:

package main

import "fmt"

// 定义一个名为apply的函数,它接收一个函数作为参数,并将参数函数应用到数字5上
func apply(f func(int, int) int) {
    result := f(5, 10)
    fmt.Println("应用结果:", result)
}

// 定义一个名为add的函数,它接收两个整数并返回它们的和
func add(a, b int) int {
    return a + b
}

func main() {
    // 将add函数作为参数传递给apply函数
    apply(add)

    // 将匿名函数作为参数传递给apply函数
    apply(func(a, b int) int {
        return a * b
    })
}

运行上面的代码,输出结果为:

应用结果: 15
应用结果: 50

在这个示例中,我们定义了一个 apply 函数,它接收一个函数作为参数,并将这个函数应用到数字5和10上。在 main 函数中,我们分别将 add 函数和一个匿名函数作为参数传递给 apply 函数,用于实现加法和乘法操作。

通过将函数作为参数和返回值,我们可以更灵活地组合和使用函数,实现更多复杂的功能。

3.7 defer函数

为什么需要defer

在函数中,程序员进程需要创建资源(比如:数据库连接、文件句柄、锁等),为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer(延时机制)。

在 Go 语言中,我们可以使用 defer 关键字延迟执行一些代码,无论外部函数执行的怎样,这些代码都会在函数返回之前被执行。

下面是一个示例,展示了 defer 的使用场景:

import "fmt"

func sum(n1 int, n2 int) int {
	defer fmt.Println("ok1 n1=", n1)
	defer fmt.Println("ok2 n2=", n2)
	res := n1 + n2
	fmt.Println("ok3 res=", res)
	return res
}

func main() {
	res := sum(10, 20)
	fmt.Println("res=", res)
}

运行上面的代码,输出结果为:

ok3 res= 30
ok2 n2= 20
ok1 n1= 10
res= 30

当go执行到一个defer时,不会立即执行defer后的语句,而是将defer后的语句压入到一个栈中,当函数执行完毕之后,再从defer栈中,一次从栈顶取出语句执行,所以从上面的案例就可以看出,先执行的是ok2语句。

3.8 作为结构体的方法

在 Go 语言中,方法是一种与特定类型关联的函数。它们可以通过定义在类型上的方法来实现某些特定操作。

下面是一个示例,展示了如何定义和使用方法:

package main

import (
    "fmt"
    "math"
)

// 定义一个名为Circle的结构体类型
type Circle struct {
    radius float64
}

// 在Circle类型上定义一个名为area的方法,它返回这个圆的面积
func (c Circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func main() {
    // 创建一个Circle实例
    c := Circle{radius: 5}

    // 调用Circle类型的方法
    fmt.Println("圆的面积:", c.area())
}

运行上面的代码,输出结果为:

圆的面积: 78.53981633974483

在这个示例中,我们定义了一个名为 Circle 的结构体类型,它包含一个半径属性。然后,在 Circle 类型上定义了一个名为 area 的方法,它用于计算圆的面积。

main 函数中,我们创建了一个 Circle 实例,并调用了 Circle 类型的 area 方法来计算面积。

通过方法,我们可以将某些操作与特定类型绑定,使得代码更加清晰和面向对象。

4 变量的作用域

  1. 函数内部声明/定义的遍历叫局部变量,作用域仅限于函数内部。

    func test() {
    	// age 和 name 的作用域就只在test函数内部
    	age := 10
    	Name := "Tom~"
    }
    
    func main() {
    }
    
  2. 函数外部声明/定义的变量叫全局变量,作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效。

    //函数外部声明/定义的变量叫全局变量,
    //作用域在整个包都有效,如果其首字母为大写,则作用域在整个程序有效
    var age int = 50
    var Name string = "jack~"
    
    //函数
    func test() {
    	//age 和 Name的作用域就只在test函数内部
    	age := 10
    	Name := "tom~"
    	fmt.Println("age=", age) // 10
    	fmt.Println("Name=", Name) // tom~
    }
    
    func main() {
    
    	fmt.Println("age=", age) //  50
    	fmt.Println("Name=", Name) // jack~
    	test()
    }
    
  3. 如果变量是在一个代码块,比如 for / if中,那么这个变量的作用域就在该代码块。

package main
import (
	"fmt"
)
func main() {

	//如果变量是在一个代码块,比如 for / if中,那么这个变量的的作用域就在该代码块

	for i := 0; i <= 10; i++ {
		fmt.Println("i=", i)
	}

	var i int //局部变量
	for i = 0; i <= 10; i++ {
		fmt.Println("i=", i)
	}

	fmt.Println("i=", i)
}

Over~~~~结束啦!!!!冲冲冲!!!

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

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

相关文章

3BHE009319R0001 UNS2881b-P,V1 l展示面向边缘人工智能应用

3BHE009319R0001 UNS2881b-P,V1 l展示面向边缘人工智能应用 ASRock Industrial展示了由第12代英特尔酷睿处理器(Alder Lake-P)支持的NUC 1200 BOX/iBOX 1200系列工业计算机&#xff0c;用于跨行业的人工智能加速。工业计算机采用高达12个内核/16个线程的高性能混合架构和高达9…

MySQL -- 库和表的操作

MySQL – 库和表的操作 文章目录 MySQL -- 库和表的操作一、库的操作1.创建数据库2.查看数据库3.删除数据库4.字符集和校验规则5.校验规则对数据库的影响6.修改数据库7.备份和恢复8.查看连接情况 二、表的操作1.创建表2.查看表结构3.修改表4.删除表 一、库的操作 注意&#xf…

针对遗留系统采取的不同演化策略

1. 改造策略 高水平、高价值区&#xff0c;即遗留系统的技术含量较高&#xff0c;本身还有极大的生命力。系统具有较高的业务价值&#xff0c;基本上能够满足企业业务运作和决策支持的需要。这种系统可能建成的时间还很短&#xff0c;对这种遗留系统的演化策略为改造。改造包括…

找不到conda可执行文件:解决方法

1.在新版本的pycharm出现的问题如下&#xff1a; 2.解决方法: 2.1 将anaconda\Scripts\conda.exe选中 2.2选择自己的anconda自己的环境&#xff0c;之后就可以正常创建conda环境

基于Tucker分解的时序知识图谱补全10.23

基于Tucker分解的时序知识图谱补全 摘要引言相关工作静态知识图谱补全时序知识图谱补全 背景提出的模型学习时间复杂度和参数增长表达能力分析 实验 摘要 知识图谱已被证明是众多智能应用的有效工具。然而&#xff0c;大量有价值的知识仍然隐含在知识图谱中。为了丰富现有的知…

异步加载 JavaScript

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

后台交互-个人中心->小程序登录微信登录接口演示,小程序授权登录理论,小程序授权登录代码演示,微信表情包存储问题

小程序登录微信登录接口演示小程序授权登录理论小程序授权登录代码演示微信表情包存储问题 1.小程序登录微信登录接口演示 推荐使用 wx.getUserProfile 获取用户信息&#xff0c;开发者每次通过该接口获取用户个人信息均需用户确认 // pages/index/index.js Page({data: {user…

24东北大学计算机计划招生数据

2.结语 24的保研名额很多&#xff0c;统考名额就这些&#xff0c;大家根据自己的情况做出选择 东大计算机不好考&#xff0c;但是不代表考不上&#xff01;加油 3.数据来源于官网 官网链接

基于深度学习实现一张单图,一个视频,一键换脸,Colab脚本使用方法,在线版本,普通人也可以上传一张图片体验机器学习一键换脸

基于深度学习实现一张单图,一个视频,一键换脸,Colab脚本使用方法,在线版本,普通人也可以上传一张图片体验机器学习一键换脸。 AI领域人才辈出,突然就跳出一个大佬“s0md3v”,开源了一个单图就可以进行视频换脸的项目。 项目主页给了一张换脸动图非常有说服力,真是一图…

python网络爬虫(二)基本库的使用urllib/requests

使用urllib 了解一下 urllib 库&#xff0c;它是 Python 内置的 HTTP 请求库&#xff0c;也就是说不需要额外安装即可使用。它包含如下 4 个模块。 request&#xff1a;它是最基本的 HTTP 请求模块&#xff0c;可以用来模拟发送请求。就像在浏览器里输入网址然后回车一样&…

【项目经理】工作流引擎

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

COS 音视频实践

对象存储 音视频处理概述-媒体处理实践-最佳实践-腾讯云 1、COS https://www.cnblogs.com/cloudstorageangel/p/15977032.html 全程&#xff1a;对象存储&#xff08;Cloud Object Storage&#xff0c;COS&#xff09;&#xff1b;腾讯云提供的对象存储服务。 可以对音视频…

目标检测的方法

目标检测大致分为两个方向:基于传统的目标检测算法和基于深度学习的目标检测算法。 1.基于传统的目标检测算法 在利用深度学习做物体检测之前,传统算法对于目标检测通常分为3个阶段:区域选取、特征提取和体征分类。 2.基于深度学习的目标检测算法 目标检测任务可分为两

【SA8295P 源码分析 (一)】111 - 使用 Infineon 工具升级DHU 的MCU 固件过程指导

【SA8295P 源码分析 一】111 - 使用 Infineon 工具升级DHU 的MCU 固件过程指导 系列文章汇总见:《【SA8295P 源码分析 (一)】系统部分 文章链接汇总 - 持续更新中》 本文链接:《【SA8295P 源码分析 (一)】111 - 使用 Infineon 工具升级DHU 的MCU 固件过程指导》 打开 Infineo…

【STM32】时钟设置函数(寄存器版)

一、STM32时钟设置函数移植 1.时钟模块回顾 一个疑问 前面代码并没有设置时钟为什么可以直接使用。 2.时钟树 3.时钟树分析 1.内部晶振&#xff08;HSI&#xff09; 内部晶振不稳定&#xff0c;当我们上电后&#xff0c;会自动产生振动&#xff0c;自动产生时钟&#xff0c;…

HBuilder打包的安卓app开屏页广告如何关闭

HBuilder打包的安卓app开屏页广告如何关闭 如上图所示&#xff0c;在打包安卓app时会默认勾选 基础开屏广告 而且无法取消 解决办法 1. 登陆 uni-ad广告联盟 网站 2. 访问广告设置链接 3. 4. 选择你的项目 5. 6. 7.

apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】

网络有很多类似的教程&#xff0c;但很多步骤不太详细。对于想接触反编译门槛的初级友友来说。操作中出现一点问题而解决不了的时候。很多都会放弃。今天的教程系列带你由浅入深的了解apk反编译操作。兴趣是最好的老师。从简单的修改apk名称到深层次的去广告 无vip等等打好基础…

向量检索库Milvus架构及数据处理流程

文章目录 背景milvus想做的事milvus之前——向量检索的一些基础近似算法欧式距离余弦距离 常见向量索引1&#xff09; FLAT2&#xff09; Hash based3&#xff09; Tree based4&#xff09; 基于聚类的倒排5&#xff09; NSW&#xff08;Navigable Small World&#xff09;图 向…

做亚马逊测评有哪些需要注意的?

做测评的注意事项有哪些? 国外的IP 养号用动态IP是不安全的&#xff0c;因为真实买家的IP地址并不会经常变化&#xff0c;也不会到处乱跳&#xff0c;所以如果要养号就需要用国外的独享家庭住宅IP地址&#xff0c;而且ip纯净度也要高&#xff0c;市面上的鲁米或者911现在基本…

Java算法做题中用到的-数据结构(对应C++的STL)【java中各种集合的api方法】

Java算法做题中用到的-数据结构&#xff08;对应C的STL&#xff09; 一、数组List初始化加入元素&#xff1a; add删除元素&#xff1a; remove&#xff08;参数是角标&#xff09;获取元素&#xff1a;getindexOf() 返回指定元素下标contains()toArray() 排序方法一&#xff1…