go语言基本操作--四

news2024/11/25 5:23:42

面向对象编程

对于面向对象编程的支持go语言设计得非常简洁而优雅。因为,Go语言并没有沿袭面向对象编程中诸多概念,比如继承(不支持继承,尽管匿名字段的内存布局和行为类似继承,但它并不是继承)、虚函数、构造函数和析构函数、隐藏的this指针等.
尽管go语言中没有封装,继承,多态这些概念,但同样通过别的方式实现这些特性:
1:封装:通过方法实现
2:继承:通过匿名字段实现
3:多态:通过接口实现

匿名字段作用—继承

一般情况下,定义结构体的时候是字段名与其类型一 一对应,实际上go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。
当匿名字段也是一个结构体的时候,那么这个结构体所拥有的全部字段都被隐式地引入了当前定义的这个结构体。

//定义一个结构体类型

type Person struct {
	name string //名字
	sex  byte   //性别
	age  int    //年龄
}

type Student struct {
	Person //只有类型 没有名字,匿名字段,继承了Person的成员
	id     int
	addr   string
}

匿名字段初始化

package main

import "fmt"

//定义一个结构体类型

type Person struct {
	name string //名字
	sex  byte   //性别
	age  int    //年龄
}

type Student struct {
	Person //只有类型 没有名字,匿名字段,继承了Person的成员
	id     int
	addr   string
}

func main() {
	//顺序初始化
	var s1 Student = Student{
		Person{"mike", 'm', 18},
		1,
		"bj",
	}
	fmt.Println("s1 = ", s1) //s1 =  {{mike 109 18} 1 bj}

	//自动推导类型
	s2 := Student{
		Person{"mike", 'm', 18},
		1,
		"bj",
	}
	fmt.Println("s2 = ", s2) //s2 =  {{mike 109 18} 1 bj}
	//%+v 显示更详细
	fmt.Printf("s2 = %+v\n", s2) //s2 = {Person:{name:mike sex:109 age:18} id:1 addr:bj}

	//指定成员初始化,没有初始化的常用自动赋值为0
	s3 := Student{id: 1}
	fmt.Printf("s3 = %+v\n", s3) //s3 = {Person:{name: sex:0 age:0} id:1 addr:}

	s4 := Student{Person: Person{name: "mike"}, id: 1}
	fmt.Printf("s4 = %+v\n", s4) //s4 = {Person:{name:mike sex:0 age:0} id:1 addr:}
}

成员的操作

package main

import "fmt"

//定义一个结构体类型

type Person struct {
	name string //名字
	sex  byte   //性别 字符类型
	age  int    //年龄
}

type Student struct {
	Person //只有类型 没有名字,匿名字段,继承了Person的成员
	id     int
	addr   string
}

func main() {
	//自动推导类型
	s1 := Student{Person{"mike", 'm', 18}, 1, "bj"}

	fmt.Println(s1.name, s1.sex, s1.id, s1.addr, s1.age) //mike 109 1 bj 18
	s1.name = "yoyo"                                     //等价于s1.Person.name = "mike"
	s1.sex = 'f'
	s1.age = 22
	s1.id = 666
	s1.addr = "wh"
	fmt.Println(s1.name, s1.sex, s1.id, s1.addr, s1.age) //yoyo 102 666 wh 22
	s1.Person = Person{"go", 'm', 23}
	fmt.Println(s1.name, s1.sex, s1.id, s1.addr, s1.age) //go 109 666 wh 23
}

同名字段

package main

import "fmt"

//定义一个结构体类型

type Person struct {
	name string //名字
	sex  byte   //性别 字符类型
	age  int    //年龄
}

type Student struct {
	Person //只有类型 没有名字,匿名字段,继承了Person的成员
	id     int
	addr   string
	name   string //和Person同名了
}

func main() {
	//声明(定义一个变量)
	var s Student
	//默认规则(就近原则),如果能在本作用域找到此成员,就操作此成员
	//如果没有找到,找到继承的字段
	s.name = "mike" //操作的是Student的name
	s.sex = 'm'
	s.age = 18
	s.addr = "bj"
	fmt.Printf("s = %+v\n", s) //s = {Person:{name: sex:109 age:18} id:0 addr:bj name:mike}

	//显示调用
	s.Person.name = "yoyo"
	fmt.Printf("s = %+v\n", s) //s = {Person:{name:yoyo sex:109 age:18} id:0 addr:bj name:mike}
}

非结构体匿名字段

package main

import "fmt"

//定义一个结构体类型

type mystr string //自定义类型,给一个类型改名

type Person struct {
	name string //名字
	sex  byte   //性别 字符类型
	age  int    //年龄
}

type Student struct {
	Person //只有类型 没有名字,匿名字段,继承了Person的成员
	int    //基础类型的匿名字段
	mystr  //基础类型的匿名字段
}

func main() {
	s := Student{Person{"mike", 'm', 18}, 666, "hehehe"}
	fmt.Printf("s = %+v\n", s) //s = {Person:{name:mike sex:109 age:18} int:666 mystr:hehehe}

	fmt.Println(s.name, s.age, s.sex, s.int, s.mystr) //mike 18 109 666 hehehe
	fmt.Println(s.Person, s.int, s.mystr)             //{mike 109 18} 666 hehehe

	s.Person = Person{"go", 'm', 22}
	fmt.Println(s.Person, s.int, s.mystr)             //{go 109 22} 666 hehehe
	fmt.Println(s.name, s.age, s.sex, s.int, s.mystr) //go 22 109 666 hehehe
}

结构体指针类型匿名字段

package main

import "fmt"

//定义一个结构体类型

type mystr string //自定义类型,给一个类型改名

type Person struct {
	name string //名字
	sex  byte   //性别 字符类型
	age  int    //年龄
}

type Student struct {
	*Person //指针类型
	id      int
	addr    string
}

func main() {
	s1 := Student{&Person{"mike", 'm', 18}, 1, "wh"}
	fmt.Println("s1 = ", s1)                             //s1 =  {0xc00008e380 1 wh}
	fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr) //mike 109 18 1 wh

	//先定义变量
	var s2 Student
	s2.Person = new(Person) //分配空间
	s2.name = "yoyo"
	s2.sex = 'm'
	s2.age = 19
	s2.id = 2
	s2.addr = "wh"
	fmt.Println("s2 = ", s2)                             //s2 =  {0xc000054400 2 wh}
	fmt.Println(s2.name, s2.sex, s2.age, s2.id, s2.addr) //yoyo 109 19 2 wh
}

方法介绍—封装

在面向对象编程中,一个对象其实也就是一个简单的值或者一个变量,在这个对象中会包含一些函数,这种带有接收者的函数,我们称为方法。本质上,一个方法则是一个和特殊关联的函数。
一个面向对象的程序会用方法来表达其属性和对应的操作,这样使用这个对象的用户就不需要直接去操作对象,而是借助方法来做这种事情。
在Go语言中,可以任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法。
方法总是绑定对象实例,并隐式将实例作为第一实参(receiver),方法的语法如下:
func (receiver ReceiverType) funcName(parameters)(results)
1:参数receiver可任意命名.如方法中未曾使用,可以省略参数.
2: 参数receiver类型可以是T或*T。基类型T不能是接口或者指针
3:不支持重载方法,也就是说,不能定义名字相同但是不同参数的方法。

面向过程和面向对象函数区别

package main

import "fmt"

// 实现2数相加
// 面向过程
func Add01(a, b int) int {
	return a + b
}

// 面向对象,方法:给某个类型绑定一个函数
type long int //改名

// tmp叫接收者,接收者就是传递的一个参数
func (tmp long) Add02(other long) long {
	return tmp + other
}

func main() {

	result := Add01(1, 1)            //普通函数调用方式
	fmt.Println("result = ", result) //result = 2

	//定义一个变量
	var a long = 2

	//调用方法格式
	add1 := a.Add02(3)
	fmt.Println("result = ", add1) //result =  5

	//面向对象只是换了一种表现形式
}

结构体类型添加方法

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

//带有接收者的函数叫方法

func (tmp Person) PrintInfo() {
	fmt.Println("tmp = ", tmp)
}

// 通过一个函数,给成员赋值
func (p *Person) SetInfo(name string, sex byte, age int) {
	p.name = name
	p.sex = sex
	p.age = age
}
func main() {
	//定义同时初始化
	p := Person{"mike", 'm', 18}
	p.PrintInfo() //tmp =  {mike 109 18}

	//定义一个结构体变量
	var p2 Person

	(&p2).SetInfo("yoyo", 'm', 19)
	p2.PrintInfo() //tmp =  {yoyo 109 19}
}
type pointer *int
//pointer 为接收者类型,它本身不能是指针类型
func (tmp pointer) test(){} //error invalid receiver type pointer

//不支持重载,只要接收者类型不一样,这个方法就算同名,也是不同方法,不会出现重复定义函数的错误

func (tmp Person) PrintInfo() {
	fmt.Println("tmp = ", tmp)
}

type char byte

func (tmp char) PrintInfo() {

}

值语义和引用语义

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

// 接收者为普通变量,非指针,值语义,一份拷贝
func (p Person) SetInfoValue(name string, sex byte, age int) {
	p.name = name
	p.sex = sex
	p.age = age
	fmt.Println("SetInfoValue p = ", p)      //SetInfoValue p =  {mike 109 19}
	fmt.Printf("SetInfoValue &p = %p\n", &p) //SetInfoValue &p = 0xc00008e3c0
}

// 接收者为指针变量,引用传递
func (p *Person) SetInfoPoubter(name string, sex byte, age int) {
	p.name = name
	p.sex = sex
	p.age = age
	fmt.Printf("SetInfoPoubter p = %p\n", &p) //SetInfoPoubter p = 0xc00008e380
	fmt.Println("SetInfoPoubter &p = ", *p)   //SetInfoPoubter &p =  {mike 109 19}
}
func main() {

	s1 := Person{"go", 'm', 18}

	fmt.Printf("&s1 = %p\n", &s1) //&s1 = 0xc00008e380
	//值语义
	s1.SetInfoValue("mike", 'm', 19)
	fmt.Println("s1 = ", s1) //s1 =  {go 109 18}

	//引用语义
	(&s1).SetInfoPoubter("mike", 'm', 19)
	fmt.Println("s1 = ", s1) //s1 =  {mike 109 19}
}

指针类型和普通类型的方法集

指针类型的方法集

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

// 接收者为普通变量,非指针,值语义,一份拷贝
func (p Person) SetInfoValue() {
	fmt.Println("SetInfoValue")
}

// 接收者为指针变量,引用传递
func (p *Person) SetInfoPoubter() {
	fmt.Println("SetInfoPoubter")
}
func main() {
	//假如,结构体是一个指针变量,它能够调用那些方法,这些方法就是一个集合,简称方法集
	p := &Person{"mike", 'm', 18}

	p.SetInfoPoubter()

	(*p).SetInfoPoubter() //把(*p)转换成p调用,等价于上面

	//内部做的转换,先把指针p,转成*p后再调用
	//(*p).SetInfoValue()
	p.SetInfoValue()
}

普通类型的方法集

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

// 接收者为普通变量,非指针,值语义,一份拷贝
func (p Person) SetInfoValue() {
	fmt.Println("SetInfoValue")
}

// 接收者为指针变量,引用传递
func (p *Person) SetInfoPoubter() {
	fmt.Println("SetInfoPoubter")
}
func main() {

	p := Person{"mike", 'm', 18}

	p.SetInfoPoubter() //内部会先把p转化为&p再调用(&p).SetInfoPoubter()

	p.SetInfoValue()
}

方法的继承

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

// Person类型,实现一个方法
func (tmp *Person) PrintInfo() {
	//PrintInfo: name = mike,sex = m, age = 18
	fmt.Printf("PrintInfo: name = %s,sex = %c, age = %d\n", tmp.name, tmp.sex, tmp.age)
}

// 有一个学生,继承Person字段,成员和方法都继承了
type Student struct {
	Person //匿名字段
	id     int
	addr   string
}

func main() {
	s := Student{Person{"mike", 'm', 18}, 666, "bj"}
	s.PrintInfo()
}

方法的重写

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

// PrintInfo Person类型,实现一个方法
func (tmp *Person) PrintInfo() {
	//PrintInfo: name = mike,sex = m, age = 18
	fmt.Printf("PrintInfo: name = %s,sex = %c, age = %d\n", tmp.name, tmp.sex, tmp.age)
}

// PrintInfo Student也实现了一个方法,这个方法和Person方法重名,这个方法叫重写
func (tmp *Student) PrintInfo() {
	//PrintInfo: name = mike,sex = m, age = 18
	fmt.Println("Student: tmp = ", tmp)   //Student: tmp =  &{{mike 109 18} 666 bj}
	fmt.Println("Student: *tmp = ", *tmp) //Student: *tmp =  {{mike 109 18} 666 bj}
}

// Student 有一个学生,继承Person字段,成员和方法都继承了
type Student struct {
	Person //匿名字段
	id     int
	addr   string
}

func main() {
	s := Student{Person{"mike", 'm', 18}, 666, "bj"}
	//就近原则:先找本作用域的方法,找不到再用继承的方法
	s.PrintInfo() //这样会调用Student的

	//显示调用继承的方法
	s.Person.PrintInfo() //PrintInfo: name = mike,sex = m, age = 18
}

方法值

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

func (p Person) SetInfoValue() {
	fmt.Printf("SetInfoValue: %p,%v\n", &p, p)
}

func (p *Person) SetInfoPointer() {
	fmt.Printf("SetInfoPointer %p, %v\n", p, *p) //SetInfoPointer 0xc00008e380, {mike 109 18}
}

func main() {

	p := Person{"mike", 'm', 18}
	fmt.Printf("main: %p,%v\n", &p, p) //main: 0xc00008e380,{mike 109 18}

	p.SetInfoPointer() //传统调用方式

	//保存方式入口地址
	pFunc := p.SetInfoPointer //这个就是方法值,调用函数时,无需再传递接收者,隐藏了接收者
	pFunc()                   //等价于p.SetInfoPointer() SetInfoPointer 0xc00008e380, {mike 109 18}

	vFunc := p.SetInfoValue
	vFunc() //等价于p.SetInfoValue() SetInfoValue: 0xc000054440,{mike 109 18} 值传递
}

方法表达式

package main

import "fmt"

type Person struct {
	name string
	sex  byte
	age  int
}

func (p Person) SetInfoValue() {
	fmt.Printf("SetInfoValue: %p,%v\n", &p, p)
}

func (p *Person) SetInfoPointer() {
	fmt.Printf("SetInfoPointer %p, %v\n", p, *p) //SetInfoPointer 0xc00008e380, {mike 109 18}
}

func main() {

	p := Person{"mike", 'm', 18}
	fmt.Printf("main: %p,%v\n", &p, p) //main: 0xc00008e380,{mike 109 18}

	p.SetInfoPointer() //传统调用方式

	//方法值,f := p.SetInfoPointer//隐藏了接收者

	//方法表达式
	f := (*Person).SetInfoPointer
	fmt.Println("=========")
	f(&p) //显示把接收者传递过去 ---->p.SetInfoPointer() SetInfoPointer 0xc0000543a0, {mike 109 18}

	f2 := (Person).SetInfoValue
	f2(p) //SetInfoValue: 0xc000054440,{mike 109 18}
}

接口类型介绍

在go语言,接口是一个自定义类型,接口类型具体描述了一系列方法的集合。
接口类型时一种抽象的类型,它不会暴露出它所代表的对象的内部值的结构和这个对象支持的基础操作的集合,它们只会展示出它们自己的方法。因此接口类型不能将其实例化。
接口定义:
1:接口命令习惯以er结尾
2:接口只有方法声明,没有实现,没有数据字段
3:接口可以匿名嵌入其他接口,或嵌入到结构中

接口的定义和实现

package main

import "fmt"

// Humaner 定义接口类型
type Humaner interface {
	//方法,只有声明,没有实现,由别的类型(自定义类型)实现
	sayhi()
}

type Student struct {
	name string
	id   int
}

// Student实现了此方法
func (tmp *Student) sayhi() {
	fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)

}

type Teacher struct {
	addr  string
	group string
}

// Teacher实现了此方法
func (tmp *Teacher) sayhi() {
	fmt.Printf("Teacher[%s, %s] sayhi\n", tmp.addr, tmp.group)

}

type MyStr string

// MyStr实现了此方法
func (tmp *MyStr) sayhi() {
	fmt.Printf("MyStr[%s] sayhi\n", *tmp)
}

type MyStr1 string

func (tmp MyStr1) sayhi() {
	fmt.Printf("MyStr1[%s] sayhi\n", tmp)
}

func main() {
	//定义接口类型的变量
	var i Humaner

	//只要实现了此接口方法的类型,那么这个类型的变量(接收者类型)就可以给i赋值
	s := &Student{"mike", 666}
	i = s
	i.sayhi() //Student[mike, 666] sayhi

	t := &Teacher{"wh", "go"}
	i = t
	i.sayhi() //Teacher[wh, go] sayhi

	var str MyStr = "hello cheng"
	i = &str
	i.sayhi() //MyStr[hello cheng] sayhi

	var str1 MyStr1 = "hello"
	i = str1
	i.sayhi() //MyStr1[hello] sayhi
}

多态的表现

package main

import "fmt"

// Humaner 定义接口类型
type Humaner interface {
	//方法,只有声明,没有实现,由别的类型(自定义类型)实现
	sayhi()
}

type Student struct {
	name string
	id   int
}

// Student实现了此方法
func (tmp *Student) sayhi() {
	fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)

}

type Teacher struct {
	addr  string
	group string
}

// Teacher实现了此方法
func (tmp *Teacher) sayhi() {
	fmt.Printf("Teacher[%s, %s] sayhi\n", tmp.addr, tmp.group)

}

type MyStr string

// MyStr实现了此方法
func (tmp *MyStr) sayhi() {
	fmt.Printf("MyStr[%s] sayhi\n", *tmp)
}

type MyStr1 string

func (tmp MyStr1) sayhi() {
	fmt.Printf("MyStr1[%s] sayhi\n", tmp)
}

// 定义一个普通函数,函数的参数为接口类型
// 只有一个函数,可以有不同表现,多态
func WhoSayHi(i Humaner) {
	i.sayhi()
}

func main() {

	s := &Student{"mike", 666}
	t := &Teacher{"wh", "go"}
	var str MyStr = "hello cheng"
	var str1 MyStr1 = "hello"
	//调用同一函数,不同表现,多态,多种形态
	WhoSayHi(s)
	WhoSayHi(t)
	WhoSayHi(&str)
	WhoSayHi(str1)

	//创建一个切片
	x := make([]Humaner, 4)
	x[0] = s
	x[1] = t
	x[2] = &str
	x[3] = str1

	//第一个返回下标,第二个返回鞋标所对应的值
	for _, data := range x {
		fmt.Println("===========")
		WhoSayHi(data)
	}
}

接口继承—(接口嵌入)

如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式地包含了interface1里面的方法。

package main

import "fmt"

// Humaner 定义接口类型
type Humaner interface { //子集
	//方法,只有声明,没有实现,由别的类型(自定义类型)实现
	sayhi()
}

type Personer interface { //超集
	Humaner //匿名字段,继承了sayhi()

	sing(lrc string)
}

type Student struct {
	name string
	id   int
}

// Student实现了此方法
func (tmp *Student) sayhi() {
	fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)

}

func (tmp *Student) sing(lrc string) {
	fmt.Println("Student在唱着:", lrc)
}

func main() {

	//定义一个接口类型的变量
	var i Personer
	s := &Student{"mike", 666}
	i = s
	i.sayhi()    //继承过来的方法 //Student[mike, 666] sayhi
	i.sing("三月") //Student在唱着: 三月
}

接口转换

package main

import "fmt"

// Humaner 定义接口类型
type Humaner interface { //子集
	//方法,只有声明,没有实现,由别的类型(自定义类型)实现
	sayhi()
}

type Personer interface { //超集
	Humaner //匿名字段,继承了sayhi()

	sing(lrc string)
}

type Student struct {
	name string
	id   int
}

// Student实现了此方法
func (tmp *Student) sayhi() {
	fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)

}

func (tmp *Student) sing(lrc string) {
	fmt.Println("Student在唱着:", lrc)
}

func main() {

	//超集可以转换为子集,反过来不可以
	var iPro Personer //超集

	iPro = &Student{"mike", 666}
	var i Humaner //子集
	//cannot use i (variable of type Humaner) as Personer value in assignment:
	//Humaner does not implement Personer (missing method sing)
	//iPro = i //error

	i = iPro //OK 超集可以转换为子集
	i.sayhi()
}

空接口

空接口不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型,它有点类似于C语言的void*类型。
在这里插入图片描述

package main

import "fmt"

func xxx(args ...interface{}) {
	
}

func main() {
	//空接口万能类型,保存任意类型的值

	var i interface{} = 1
	fmt.Println("i = ", i)

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

通过if实现类型断言

在这里插入图片描述

package main

import "fmt"

type Student struct {
	name string
	id   int
}

func main() {

	i := make([]interface{}, 3)

	i[0] = 1                    //int
	i[1] = "hello go"           //string
	i[2] = Student{"mike", 666} //Student

	//类型查询,类型断言
	//第一个返回下标,第二个返回下标对应的值,data是i[0],i[1],i[2]
	for index, data := range i {
		//第一个返回值,接口变量本身,第二个返回判断结果的真假
		if value, ok := data.(int); ok == true {
			fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value) //x[0] 类型为int,内容为1
			fmt.Println("int data = ", data)                 //int data =  1
			fmt.Println("------------------")
		} else if value, ok := data.(string); ok == true {
			fmt.Printf("x[%d] 类型为string, 内容为%s\n", index, value) //x[1] 类型为string, 内容为hello go
			fmt.Println("string data = ", data)                  //string data =  hello go
			fmt.Println("------------------")
		} else if value, ok := data.(Student); ok == true {
			fmt.Printf("x[%d] 类型为Student, 内容为name = %s, id = %d\n", index, value.name, value.id) //x[2] 类型为Student, 内容为name = mike, id = 666
			fmt.Println("Student data = ", data)                                                 //Student data =  {mike 666}
			fmt.Println("------------------")
		}
	}
}

通过switch实现类型断言

package main

import "fmt"

type Student struct {
	name string
	id   int
}

func main() {

	i := make([]interface{}, 3)

	i[0] = 1                    //int
	i[1] = "hello go"           //string
	i[2] = Student{"mike", 666} //Student

	//类型查询,类型断言
	//第一个返回下标,第二个返回下标对应的值,data是i[0],i[1],i[2]
	for index, data := range i {
		switch value := data.(type) { //type参数类型
		case int:
			fmt.Printf("x[%d] 类型为int,内容为%d\n", index, value) //x[0] 类型为int,内容为1
			fmt.Println("int data = ", data)                 //int data =  1
			fmt.Println("------------------")
		case string:
			fmt.Printf("x[%d] 类型为string, 内容为%s\n", index, value) //x[1] 类型为string, 内容为hello go
			fmt.Println("string data = ", data)                  //string data =  hello go
			fmt.Println("------------------")
		case Student:
			fmt.Printf("x[%d] 类型为Student, 内容为name = %s, id = %d\n", index, value.name, value.id) //x[2] 类型为Student, 内容为name = mike, id = 666
			fmt.Println("Student data = ", data)                                                 //Student data =  {mike 666}
			fmt.Println("------------------")
		}
	}
}

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

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

相关文章

16字节协议的串口通信

1.协议要求 协议为帧传输,一共16字节。主要是2字节的固定帧头 EB 90,2字节的帧计数(用来计数发出的帧),10字节的数据和2字节的校验位 帧头:2字节,固定值 8’HEB、8’H90 帧计数:2字节,用来说明发出去帧是…

esp32s3实现openmv

演示参考下方视频 源码链接在视频末尾获取点击查看视频 摄像头引脚配置 烧录配置

【Linux】进程基础概念【下篇】

目录 1. 基本概念 2. 常见环境变量 常见环境变量指令 (1. PATH (2. HOME (3. SHELL 3.环境变量的组织形式 (1)通过代码如何获取环境变量 (2)普通变量与环境变量的区别 (3&…

Vue+NodeJS实现邮件发送

一.邮箱配置 这里以QQ邮箱为例,网易邮箱类似. 设置->账号 二.后端服务搭建 index.js const express require(express) const router require(./router); const app express()// 使用路由文件 app.use(/,router);app.listen(3000, () > {console.log(server…

大学大创项目:手机室内AR导航APP项目思路

文章目录 一、最初的项目思路二、建图和定位分离的项目思路1、建图2、定位 个人见解,如有错误,请多包涵 一、最初的项目思路 在大创项目的开始,将手机确定为应用设备,传感器确定为相机。 由于知识储备的原因,在头一次…

Jenkins实现基础CI操作

操作截图 代码push进gitlab Jenkins拉取gitlab代码 在容器内Jenkins拉取的代码

app备案ios的公钥和md5的获取方法

最近app需要备案才能上架了 但是app备案的时候,特别是ios备案的时候需要提供app的公钥和md5比较头大,无论是android系统还是ios系统,都需要提供证书的公钥和md5。 获取这个公钥和md5真的好麻烦,好像各种工具都没有提供获取这些信…

java数据结构1------深入学习ArrayList

目录 一、概念 二、源码分析 1、属性 2、构造器 ①空构造 ②指定初始容量(initialCapacity)构造器 ②参数为Collection的构造器 3、常用方法 ①public boolean add(E e) ②public void add(int index, E element) ③其他方法 三、总结 一、概念…

【ARM AMBA5 CHI 入门 12 -- CHI 总线学习 】

文章目录 介绍CHI 特点Layers of the CHI architectureTopology Node TypeTransaction 分类Transaction 路由SAM 介绍Node ID 节点间数据怎么传输的呢? 介绍 CHI 的全称是 Coherent Hub Interface。所以从名字就能看出,CHI要解决什么问题了。按照惯例&a…

思维导图怎么变成ppt?4个思维导图一键生成ppt的方法

做好的思维导图如何变成一份ppt?本文罗列了4个可行方法,一起来看看吧。 一 直接复制粘贴 这是最简单的方法,虽然这样可能会花费一些时间,但可以确保内容排版和布局与你想要的一致。当然,我们大可使用更高效的方法。…

NLP(2)--Transformer

目录 一、Transformer概述 二、输入和输出 三、Encoder 四、Decoder 五、正则化处理 六、对于结构的改进? 七、AT vs NAT 八、Cross-attention 一、Transformer概述 Transformer模型发表于2017年Google团队的Attention is All you need这篇论文,…

七、SSM 框架整合

目前已经学习了 MyBatis 框架,Spring 框架,以及Spring MVC 框架。现阶段学习将这三个框架整合到一起,实现简单的前后端交互的曾删改差功能页面。 Mybatis 框架主要负责数据库的操作问题,以及数据回显。该框架将 SQL 与 Jav…

Browserslist 信息和配置使用整理

我们可以在各种前端工程看到 Browserslist 的配置身影,看似简单但实际上可能会有暗坑导致线上兼容问题,借此文来整理下 Browserslist 的信息。 Browserslist 是由 Autoprefixer 团队维护的一个开源项目,用于自动处理 CSS 和 JavaScript 文件…

opencv识别一张图片的多个红框,并截取红框的内容

需求 需要获取图片的红框的内容,实体的图片我就不放了 获取红框 先截取获得图片的多个轮廓 import cv2 import numpy as np # 加载图像并转换为灰度图像 image cv2.imread(image6.jpg) gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 应用高斯模糊以减…

基本的 Linux 命令以及 Linux 目录结构

目录 什么是Linux? ls - 列出文件和目录 pwd - 显示当前工作目录 cd - 切换目录 mkdir - 创建目录 touch - 创建空文件 rm - 删除文件和目录 cp - 复制文件和目录 mv - 移动和重命名文件和目录 文件系统基础 Linux 操作系统是开源且强大的操作系统&…

流媒体之推流和拉流

推流:将直播内容推送至服务器的过程 拉流:为服务器已有直播内容,用指定地址进行拉取的过程 什么是推流? 推流,指的是把采集阶段封包好的内容传输到服务器的过程。其实就是将现场的视频信号传到网络的过程。“推流”…

D. Sorting By Multiplication(贪心)

Problem - D - Codeforces 给定一个长度为n的数组a,由正整数组成。 您可以对该数组执行以下操作任意次数(可能为零): 选择三个整数l、r和x,使得1≤l≤r≤n,并将满足l≤i≤r的每个ai乘以x。 请注意&#…

操作系统内存(32位为例)

0、OS能使用最大的虚拟内存和物理内存 最大的虚拟内存与寻址总线有关。一般是40根,对应256T 最大的物理内存与PTE的位数有关。 10-10-12分页模式下是32位,所以最大寻址空间就4G 1、CPU分页模式 分类 还有5-level,一般适用于大型服务器。…

【Springcloud】Seata分布式事务

【Springcloud】Seata分布式事务 【一】基本介绍(1)什么是分布式事务(2)为什么要使用分布式事务(3)seata分布式事务 【二】下载方式【1】Windows平台安装包下载 【三】如何使用【1】创建相关测试数据库和表…

每日刷题-1

目录 一、选择题 二、编程题 1、组队竞赛 2、删除公共字符 一、选择题 1、 解析:%s遇到\0会停止,%m.ns中m表示字符串宽度,n表示左起取目标字符串n个字符,右对齐,(如果想要左对齐,可以写成%-m.n…