go中的结构体

结构体的定义

以学生结构体为例,如下:

type Student struct {name stringage  int
}

同类型的可以写在一行:

type Student struct {name,course stringage  int
}

结构体初始化

方法1:使用var关键字

package mainimport "fmt"type Student struct {name stringage  int
}func main() {var s Studentfmt.Printf("s=%#v\n", s) 
}

方法2:使用值或键值对初始化

方法2.1:使用值初始化写法

s:= Student{"cc",18,
}

如果{}在一行,逗号可以省略

s:=Student{"cc",18}

方法2.2:使用键值对初始化写法

s:=Student{name:"cc",age:18,
}

方法2.3:对结构体指针进行键值对初始化

s:=&Student{name:"cc",age:18,
}

demo:

package mainimport "fmt"type Student struct {name stringage  int
}func main() {//方法1var s=Student{name:"cc",age:18,}//方法2.1s:=Student{"cc",18,}//方法2.2s:=Student{name:"cc",age:18,}fmt.Printf("s=%#v\n", s) //方法2.3:结构体指针s:=&Student{name:"cc",age:18,}fmt.Printf("s=%#v\n", s) }

方法3:给结构体成员赋值的方式进行初始化

demo

package mainimport ("fmt"
)type Student struct {name stringage  int
}func main() {var s Studentfmt.Printf("s=%v\n", s)s.name = "cc"s.age = 18fmt.Printf("p1=%v\n", s)fmt.Printf("p1=%#v\n", s)
}

匿名结构体与结构体的匿名字段

在一些临时数据结构等场景下可以使用匿名结构体

import ("fmt"
)func main() {var user struct {Name stringAge  int}user.Name = "pprof.cn"user.Age = 18fmt.Printf("%#v\n", user)
}

输出结果:

struct { Name string; Age int }{Name:"pprof.cn", Age:18}

结构体的字段定义时可以没有字段名,这种字段被称为匿名字段

package mainimport ("fmt"
)//Person 结构体
type Person struct {stringint
}func main() {p1 := Person{"pprof.cn",18,}fmt.Printf("%#v\n", p1)        //main.Person{string:"pprof.cn", int:18}fmt.Println(p1.string, p1.int) //pprof.cn 18
}

匿名字段 默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中 同种类型的匿名字段只能有一个

结构体指针

除了上面几种实例化结构体方式,还可以通过new实例化结构体,返回指向结构体的指针

package mainimport ("fmt"
)type person struct {name stringcity stringage  int8
}func main() {var p2 = new(person)fmt.Printf("%T\n", p2)     fmt.Printf("p2=%#v\n", p2) 
}

输出结果:

*main.person
p2=&main.person{name:"", city:"", age:0}

Go语言中支持对结构体指针直接使用.来访问结构体的成员

package mainimport ("fmt"
)type person struct {name stringcity stringage  int8
}func main() {var p2 = new(person)  //p2 是一个结构体指针p2.name = "测试"      //对结构体指针直接使用`.`来访问结构体的成员p2.age = 18p2.city = "北京"fmt.Printf("p2=%#v\n", p2)
}

输出结果:

p2=&main.person{name:"测试", city:"北京", age:18}

p2.name = "测试"其实在底层是(*p2).name = "测试",这是Go语言帮我们实现的语法糖。

取结构体的地址实例化

使用&对结构体变量进行取地址操作相当于对该结构体类型进行了一次 new 实例化操作。

package mainimport ("fmt"
)type person struct {name stringcity stringage  int8
}func main() {p3 := &person{}fmt.Printf("%T\n", p3)     //*main.personfmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"", city:"", age:0}p3.name = "博客"p3.age = 30p3.city = "成都"fmt.Printf("p3=%#v\n", p3) //p3=&main.person{name:"博客", city:"成都", age:30}
}

输出结果:

*main.person
p3=&main.person{name:"", city:"", age:0}
p3=&main.person{name:"博客", city:"成都", age:30}

结构体作为函数参数

  1. 实例1:将结构体作为函数参数
package mainimport "fmt"type Books struct {title   stringauthor  stringsubject stringbook_id int
}func main() {var Book1 Books /* 声明 Book1 为 Books 类型 */var Book2 Books /* 声明 Book2 为 Books 类型 *//* book 1 描述 */Book1.title = "Go 语言"Book1.author = "www.runoob.com"Book1.subject = "Go 语言教程"Book1.book_id = 6495407/* book 2 描述 */Book2.title = "Python 教程"Book2.author = "www.runoob.com"Book2.subject = "Python 语言教程"Book2.book_id = 6495700/* 打印 Book1 信息 */printBook(Book1)/* 打印 Book2 信息 */printBook(Book2)
}func printBook(book Books) {fmt.Printf("Book title : %s\n", book.title)fmt.Printf("Book author : %s\n", book.author)fmt.Printf("Book subject : %s\n", book.subject)fmt.Printf("Book book_id : %d\n", book.book_id)
}

输出结果:

Book title : Go 语言
Book author : www.runoob.com
Book subject : Go 语言教程
Book book_id : 6495407
Book title : Python 教程
Book author : www.runoob.com
Book subject : Python 语言教程
Book book_id : 6495700

实例2:将结构体指针作为函数参数

package mainimport "fmt"type Books struct {title   stringauthor  stringsubject stringbook_id int
}func main() {var Book1 Books /* 声明 Book1 为 Books 类型 */var Book2 Books /* 声明 Book2 为 Books 类型 *//* book 1 描述 */Book1.title = "Go 语言"Book1.author = "www.runoob.com"Book1.subject = "Go 语言教程"Book1.book_id = 6495407/* book 2 描述 */Book2.title = "Python 教程"Book2.author = "www.runoob.com"Book2.subject = "Python 语言教程"Book2.book_id = 6495700/* 打印 Book1 信息 *///地址就是一个指针,指针的实质就是一个地址printBook(&Book1)/* 打印 Book2 信息 */printBook(&Book2)
}
func printBook(book *Books) {fmt.Printf("Book title : %s\n", book.title)fmt.Printf("Book author : %s\n", book.author)fmt.Printf("Book subject : %s\n", book.subject)fmt.Printf("Book book_id : %d\n", book.book_id)
}

结构体内存布局

结构体内存布局是连续的

package mainimport "fmt"type test struct {a int8b int8c int8d int8
}func main() {n := test{1, 2, 3, 4,}fmt.Printf("n.a %p\n", &n.a)fmt.Printf("n.b %p\n", &n.b)fmt.Printf("n.c %p\n", &n.c)fmt.Printf("n.d %p\n", &n.d)
}

输出结果:

n.a 0xc00000a198
n.b 0xc00000a199
n.c 0xc00000a19a
n.d 0xc00000a19b

构造函数

构造函数是一种特殊的函数,用来在对象实例化的时候初始化对象的成员变量。

package mainimport "fmt"type person struct {name stringcity stringage  int8
}func main() {p9 := newPerson("pprof.cn", "测试", 90)fmt.Printf("%#v\n", p9)}//构造函数,用于初始化结构体person
func newPerson(name, city string, age int8) *person {return &person{name: name,city: city,age:  age,}
}

输出结果:

&main.person{name:"pprof.cn", city:"测试", age:90}

方法和接收器

1、为结构体添加方法

package maintype Bag struct {items []int
}//定义在背包结构体上的名为Insert的方法
func (b *Bag) Insert(itemid int) {b.items = append(b.items, itemid)
}
func main() {b := new(Bag)//在结构体b上调用方法b.Insert(1001)
}

2、接收器——方法作用的对象

2、1指针类型的接收器

指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。

由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。

在下面的例子,使用定义一个 Property 结构体,为 Property 添加 SetValue() 方法以封装设置属性的过程,通过属性的 Value() 方法可以重新获得属性的数值,使用属性时,通过 SetValue() 方法的调用,可以达成修改属性值的效果。

package main
import "fmt"
// 定义结构体 Property 
type Property struct {value int  // 属性值
}
// 设置 Property 值
func (p *Property) SetValue(v int) {// 修改p的成员变量p.value = v
}
// 取 Property 值
func (p *Property) Value() int {return p.value
}
func main() {// 实例化 Property p := new(Property)// 设置值p.SetValue(100)// 打印值fmt.Println(p.Value())
}

2、2 非指针类型的接收器

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。需要辅以 return+赋值 实现真正的修改。

package main
import ("fmt"
)
// 定义点结构
type Point struct {X intY int
}
// 非指针接收器的加方法
func (p Point) Add(other Point) Point {// 成员值与参数相加后返回新的结构体return Point{p.X + other.X, p.Y + other.Y}
}
func main() {// 初始化点p1 := Point{1, 1}p2 := Point{2, 2}// 与另外一个点相加result := p1.Add(p2)// 输出结果fmt.Println(result)
}

输出结果:

{3 3}

由于例子中使用了非指针接收器,Add() 方法变得类似于只读的方法,Add() 方法内部不会对成员进行任何修改。

指针和非指针接收器的使用场景

在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器。大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。

什么时候应该使用指针类型接收者?

需要修改接收者中的值接收者是拷贝代价比较大的大对象保证一致性,如果有某个方法使用了指针接收者,那么其他的方法也应该使用指针接收者。

嵌套结构体

一个结构体中可以嵌套包含另一个结构体或结构体指针

package mainimport ("fmt"
)//Address 地址结构体
type Address struct {Province stringCity     string
}//User 用户结构体
type User struct {Name    stringGender  stringAddress Address
}func main() {user1 := User{Name:   "pprof",Gender: "女",Address: Address{Province: "黑龙江",City:     "哈尔滨",},}fmt.Printf("user1=%#v\n", user1) //user1=main.User{Name:"pprof", Gender:"女", Address:main.Address{Province:"黑龙江", City:"哈尔滨"}}
}

输出结果:

user1=main.User{Name:"pprof", Gender:"女", Address:main.Address{Province:"黑龙江", City:"哈尔滨"}}

嵌套匿名结构体

package mainimport ("fmt"
)//Address 地址结构体
type Address struct {Province stringCity     string
}//User 用户结构体
type User struct {Name    stringGender  stringAddress //匿名结构体
}func main() {var user2 Useruser2.Name = "pprof"user2.Gender = "女"user2.Address.Province = "黑龙江"   //通过匿名结构体.字段名访问user2.City = "哈尔滨"               //可以直接访问匿名结构体的字段名fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"pprof", Gender:"女", Address:main.Address{Province:"黑龙江", City:"哈尔滨"}}
}

输出结果:

user2=main.User{Name:"pprof", Gender:"女", Address:main.Address{Province:"黑龙江", City:"哈尔滨"}}

当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。

嵌套结构体的字段名冲突

嵌套结构体内部可能存在相同的字段名。这个时候为了避免歧义需要指定具体的内嵌结构体的字段。

package mainimport ("fmt"
)//Address 地址结构体
type Address struct {Province   stringCity       stringCreateTime string
}//Email 邮箱结构体
type Email struct {Account    stringCreateTime string
}//User 用户结构体
type User struct {Name   stringGender stringAddressEmail
}func main() {var user3 Useruser3.Name = "pprof"user3.Gender = "女"// user3.CreateTime = "2019" //ambiguous selector user3.CreateTimeuser3.Address.CreateTime = "2000" //指定Address结构体中的CreateTimeuser3.Email.CreateTime = "2000"   //指定Email结构体中的CreateTimefmt.Printf("user3=%#v\n", user3)
}

输出结果:

user3=main.User{Name:"pprof", Gender:"女", Address:main.Address{Province:"", City:"", CreateTime:"2000"}, Email:main.Email{Account:"", CreateTime:"2000"}}

如果直接使用user3.CreateTime = "2000"会报错:ambiguous selector user3.CreateTime

结构体的继承

package mainimport ("fmt"
)//动物结构体
type Animal struct {name string
}//动物结构体的move方法
func (a *Animal) move() {fmt.Printf("%s会动!\n", a.name)
}//狗结构体
type Dog struct {Feet    int8*Animal //通过嵌套匿名结构体实现继承
}func (d *Dog) wang() {fmt.Printf("%s会汪汪汪~\n", d.name)
}func main() {d1 := &Dog{Feet: 4,Animal: &Animal{ //注意嵌套的是结构体指针name: "乐乐",},}d1.wang() d1.move() 
}

输出结果:

乐乐会汪汪汪~
乐乐会动!

结构体与JSON序列化

什么是对象序列化呢?

序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

通俗讲呢:对象序列化就是指将对象的状态转换为字符串。

Json语法规则:

  • 数据在键值对中
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

json格式1:

{ "firstName":"John" , "lastName":"Doe" }

json格式2:

{"employees": [{ "firstName":"John" , "lastName":"Doe" },{ "firstName":"Anna" , "lastName":"Smith" },{ "firstName":"Peter" , "lastName":"Jones" }]
}

json格式3:

var employees = [{ "firstName":"Bill" , "lastName":"Gates" },{ "firstName":"George" , "lastName":"Bush" },{ "firstName":"Thomas" , "lastName": "Carter" }
];

demo:

package mainimport ("encoding/json""fmt"
)//Student 学生
type Student struct {ID     intGender stringName   string
}//Class 班级
type Class struct {Title    stringStudents []*Student
}func main() {c := &Class{Title:    "101",Students: make([]*Student, 0, 200),}for i := 0; i < 10; i++ {stu := &Student{Name:   fmt.Sprintf("stu%02d", i),Gender: "男",ID:     i,}c.Students = append(c.Students, stu)}//JSON序列化:结构体-->JSON格式的字符串data, err := json.Marshal(c)if err != nil {fmt.Println("json marshal failed")return}fmt.Printf("json:%s\n", data)//JSON反序列化:JSON格式的字符串-->结构体str := `{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},            {"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}`c1 := &Class{}err = json.Unmarshal([]byte(str), c1)if err != nil {fmt.Println("json unmarshal failed!")return}fmt.Printf("%#v\n", c1)
}

输出结果:

json:{"Title":"101","Students":[{"ID":0,"Gender":"男","Name":"stu00"},{"ID":1,"Gender":"男","Name":"stu01"},{"ID":2,"Gender":"男","Name":"stu02"},{"ID":3,"Gender":"男","Name":"stu03"},{"ID":4,"Gender":"男","Name":"stu04"},{"ID":5,"Gender":"男","Name":"stu05"},{"ID":6,"Gender":"男","Name":"stu06"},{"ID":7,"Gender":"男","Name":"stu07"},{"ID":8,"Gender":"男","Name":"stu08"},{"ID":9,"Gender":"男","Name":"stu09"}]}
&main.Class{Title:"101", Students:[]*main.Student{(*main.Student)(0xc0000749c0), (*main.Student)(0xc0000749f0), (*main.Student)(0xc000074a20), (*main.Student)(0xc000074a50), (*main.Student)(0xc000074ab0), (*main.Student)(0xc000074ae0), (*main.Student)(0xc000074b10), (*main.Student)(0xc000074b40), (*main.Student)(0xc000074b70), (*main.Student)(0xc000074ba0)}}

结构体标签(Tag)

Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。

Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:

`key1:"value1" key2:"value2"`

结构体标签由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔。 注意事项: 为结构体编写Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在key和value之间添加空格。

例如我们为Student结构体的每个字段定义json序列化时使用的Tag:

package mainimport ("encoding/json""fmt"
)//Student 学生
type Student struct {ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的keyGender string //json序列化是默认使用字段名作为keyname   string //私有不能被json包访问
}func main() {s1 := Student{ID:     1,Gender: "女",name:   "pprof",}data, err := json.Marshal(s1)if err != nil {fmt.Println("json marshal failed!")return}fmt.Printf("json str:%s\n", data) 
}

输出结果:

json str:{"id":1,"Gender":"女"}

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

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

相关文章

oracle怎么删除表索引

Oracle是目前常用的企业级关系型数据库管理系统&#xff0c;用于存储和管理大量数据。在Oracle中&#xff0c;表索引是用于提高查询效率的重要组成部分&#xff0c;但也有时候需要删除表索引。本文将介绍如何在Oracle中删除表索引。 一、查看表索引 在删除表索引之前&#xff…

uniapp 微信小程序 锚点跳转

uniapp文档 以下是我遇到的业务场景&#xff0c;是点击商品分类的某一类 然后页面滚动至目标分类&#xff0c; 首先第一步是设置锚点跳转的目的地&#xff0c;在目标的dom上面添加id属性 然后给每个分类每一项添加点击事件&#xff0c;分类这里的item数据里面有一字段是和上…

SpringBoot初级开发--多环境配置的集成(9)

在Springboot的开发中&#xff0c;我们经常要切换各种各样的环境配置&#xff0c;比如现在是开发环境&#xff0c;然后又切换到生产环境&#xff0c;这个时候用多环境配置就是一个明智的选择。接下来我们沿用上一章的工程来配置多环境配置工程。 1.准备多环境配置文件 这里我…

Flutter 安装教程 + 运行教程

1.下载依赖 https://flutter.cn/docs/get-started/install/windows 解压完后根据自己的位置放置&#xff0c;如&#xff08;D:\flutter&#xff09; 注意 请勿将 Flutter 有特殊字符或空格的路径下。 请勿将 Flutter 安装在需要高权限的文件夹内&#xff0c;例如 C:\Program …

Redis 教程 - 主从复制

Redis 教程 - 主从复制 Redis 支持主从复制&#xff08;Master-Slave Replication&#xff09;&#xff0c;通过主从复制可以将一个 Redis 服务器&#xff08;主节点&#xff09;的数据复制到其他 Redis 服务器&#xff08;从节点&#xff09;&#xff0c;以实现数据的冗余备份…

Unity List相关问题

1、list随机数值&#xff0c;重复的数量不超过指定大小。 using System.Linq; private List<int> iconIndexs; for (int i 0; i < 5; i) {int newIndex Random.Range(0, 3);// 检查列表中已有的相同元素的数量int count iconIndexs.Count(x > x newIndex);// …

FireFox禁用HTTP2

问题 最近需要调试接口&#xff0c;但是&#xff0c;Chrome都是强制使用h2协议&#xff0c;即HTTP/2协议。为了排除h2协议排除对接口调用的影响&#xff0c;需要强制浏览器使用HTTP1协议。 解决 FireFox 设置firefox的network.http.http2.enabled为禁用&#xff0c;这样就禁…

[ros][ubuntu]ros在ubuntu18.04上工作空间创建和发布一个话题

构建catkin工作空间 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src catkin_init_workspace cd ~/catkin_ws/ catkin_make 配置环境变量 echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc source ~/.bashrc 检查环境变量 echo $ROS_PACKAGE_PATH…

【NVIDIA CUDA】2023 CUDA夏令营编程模型(二)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Vue3 select循环多个,选项option不能重复被选

Vue3 select循环多个&#xff0c;选项option不能重复被选 环境&#xff1a;vue3tsviteelement plus 实现目标&#xff1a;Vue3 select循环多个&#xff0c;当其中一个option值被选后&#xff0c;其他select里面不能再重复选择该option值。第二种&#xff0c;当其中一个option值…

SNN论文总结

Is SNN a great work ? Is SNN a convolutional work ? ANN的量化在SNN中是怎么体现的&#xff0c;和threshold有关系吗&#xff0c;threshold可训练和这个有关吗&#xff08;应该无关&#xff09; 解决过发放不发放的问题。 Intuation SNN编码方式 Image to spike patter…

后端面试话术集锦第 十 篇:springMVC面试话术

这是后端面试集锦第十篇博文——springMVC面试话术❗❗❗ 1. 介绍一下springMVC springmvc是一个视图层框架,通过MVC模型让我们很方便的接收和处理请求和响应。 我给你说说他里边的几个核心组件吧: 它的核心控制器是DispatcherServlet,他的作用是接收用户请求,然后给用户…

SASS常用内置函数

1&#xff0c;math 引入&#xff1a;use "sass:math"; 常用函数&#xff1a; ceil($number) - 向上取整floor($number) - 向下取整round($number) - 四舍五入max($number...) - 比较若干数值并取最大值min($number...) - 比较若干数值并取最小值random() - 取0~1之…

C++项目:网络版本在线五子棋对战

目录 1.项目介绍 2.开发环境 3.核心技术 4. 环境搭建 5.websocketpp 5.1原理解析 5.2报文格式 5.3websocketpp常用接口介绍 5.4websocket服务器 6.JsonCpp使用 6.1Json数据格式 6.2JsonCpp介绍 7.MySQL API 7.1MySQL API介绍 7.2MySQL API使用 7.3实现增删改查…

TCP之超时重传、流量控制和拥塞控制

一、超时重传 TCP超时重传是TCP协议中的一种机制&#xff0c;用于在发生丢包或数据包未及时确认的情况下&#xff0c;重新发送未确认的数据段。 当发送方发送一个数据段后&#xff0c;会启动一个定时器&#xff08;称为超时计时器&#xff09;&#xff0c;等待接收方的确认。…

kafka如何避免消费组重平衡

目录 前言&#xff1a; 协调者 重平衡的影响 避免重平衡 重平衡发生的场景 参考资料 前言&#xff1a; Rebalance 就是让一个 Consumer Group 下所有的 Consumer 实例就如何消费订阅主题的所有分区达成共识的过程。在 Rebalance 过程中&#xff0c;所有 Consumer 实例…

大数据精准营销获客能为企业带来哪些东西?

广告圈里一句名言:我知道我的广告浪费了一半&#xff0c;但我不知道浪费了哪一半。当前&#xff0c;越来越多的企业在大数据思维指导下进行广告投放&#xff0c;广告能通过对人群的定向&#xff0c;投放给准确的目标顾客&#xff0c;特别是互联网广告现在能够做到根据不同的人向…

XSSchallenge1-20

test1 第一题直接在test插入XSS代码即可 test2 第二关对内容进行”“包裹 这里可以采用”>来绕过 test3 代码审计发现这里用了htmlspecialchars函数&#xff0c;这个函数对<>和’ “等进行了转义&#xff0c;这里可以用事件来绕过 test4 这里用了str_replace&a…

GIT使用教程(超详细)

目录 前言 1 git安装 2 增加git账户 3 git全局参数配置 4 创建本地仓库 5 关联远程分支 6 删除远程分支关联 7. 删除分支 8 git stash 9 git reset 10 git checkout 11 合并 12 git log 13 git提交模板 &#x1f388;个人主页&#x1f388;&#xff1a;li…

14家展商集中亮相!8月30-31日,智能汽车软件与座舱车联大会

过去几年&#xff0c;在特斯拉及新势力的带动下&#xff0c;车企的盈利模式正在寻求从“一次售卖”转变为“硬件预埋&#xff0b;软件付费解锁”&#xff0c;背后是驱动汽车软件架构的迭代&#xff0c;即从面向信号的软件架构&#xff0c;过渡至面向服务的SOA架构。 同时&#…