马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
1.简介
- go也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。以是说go支持面向对象编程特性是比力精确的。
- go没有类(class),go语言的布局体(struct)和别的编程语言的类(class)有划一的职位,你可以明白go是基于struct来实现OOP特性的。
- go面向对象编程非常轻便,去掉了传统OOP语言的继续、方法重载、构造函数和析构函数、隐蔽的this指针等。
- go仍旧有面向对象编程的继续、封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继续:go没有extends关键字,继续是通过匿名字段来实现。
- go面向对象(OOP)很优雅,OOP自己就是语言范例体系(type system)的一部分,通过接口(interface)关联,耦合性低,也非常机动。也就是说在go中面向接口编程黑白常告急的特性。
2.type关键词自界说范例和范例别名
2.1自界说范例
在go语言中有一些根本的数据范例,比如string、int、bool等数据范例,可以用type关键字自界说范例。
语法: type comstomInt int
将comstomInt 界说为int范例,通过type关键字的界说,comstomInt就是一种新的范例,comstomInt和int不是同一范例,它具有int的特性。- type comstomInt int
- var a comstomInt = 3
- var b int = 3
- fmt.Printf("a:%v %T\n", a, a) //a:3 main.comstomInt
- fmt.Printf("b:%v %T\n", b, b) //b:3 int
复制代码 2.2范例别名
范例别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一范例。就像外号和真实姓名都是指的同一个人。
语法: type intAlias=int
我们之前见过的rune和byte就是范例别名:
type byte = uint8
type rune = int32
2.3自界说范例和范例别名的区别
范例别名与自定范破例貌上看只有一个等号的差异,我们通过下面的这段代码来明白他们之间的却别。- type comstomInt int
- type intAlias = int
- func main() {
- var a intAlias = 3
- fmt.Printf("a:%v %T\n", a, a) //a:3 int
- var b comstomInt = 3
- fmt.Printf("b:%v %T\n", b, b) //b:3 main.comstomInt
- }
复制代码 效果体现a的范例时int范例。b的范例时main.comstomInt,体现main包下界说的comstomInt范例。
3.布局体的界说
使用type和struct关键字来界说布局体,语法如下:
type 范例名 struct{
属性1 范例
属性2 范例
...
}
表明:
- 范例名:体现自界说布局体的名称,在一个包内不能重复。(首字母大写可以外部访问)
- 属性:体现布局体字段名,布局体中的字段必须唯一。(首字母大写可以外部访问)
- 范例:体现布局体属性的详细范例。
举个例子,我们界说一个门生Student的布局体:- type Student struct {
- Name string
- Number int
- Sex int
- Age int
- }
复制代码 同样范例的字段也可以写在一行。- type Student struct {
- Name string
- Number,Sex,Age int
- }
复制代码 4.布局体的实例化
简述:只有当布局体实例化时,才会真正地分配内存。也就是必须示例化以后才气使用布局体的字段。
- 布局体是自界说的数据范例,代表一类事物。
- 布局体变量(实例)是详细的,实际的,代表一个详细变量。
- 同一个布局体变量(实例)之间是相对独立的,变量不会相互影响。
4.1第一种方法
布局体自己也是一种数据范例,我们可以像声明内置范例一样使用var关键字声明布局提范例。
var 布局体实例 布局体范例- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- var s1 Student
- s1.Name = "韩梅梅"
- s1.Number = 20250306123
- fmt.Printf("s1=%#v\n", s1)//s1=main.Student{Name:"韩梅梅", Number:20250306123}
- }
复制代码 4.2第二种方法
可以通过new关键字对布局体举行实例化,得到的是详细的所在。- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- s1 := new(Student)
- s1.Name = "韩梅梅"
- s1.Number = 20250306123
- fmt.Printf("s1=%#v\n", s1) //s1=&main.Student{Name:"韩梅梅", Number:20250306123}
- fmt.Println(s1.Name) //韩梅梅
- fmt.Println((*s1).Name) //韩梅梅
- }
复制代码 从效果可以看出s1是一个布局体指针。
留意:在go中支持对布局体指针直接使用点(.)来访问布局体成员。s1. Name和(*s1).Name输出是一样的,go计划者为了步调员使用方便,底层会对布局体举行处理处罚。
4.3第三种方法
使用&对布局体举行取所在使用相称于对该布局体范例举行了new的实例化使用。- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- s1 := &Student{}
- s1.Name = "韩梅梅"
- s1.Number = 20250306123
- fmt.Printf("s1=%#v\n", s1) //s1=&main.Student{Name:"韩梅梅", Number:20250306123}
- fmt.Println(s1.Name) //韩梅梅
- fmt.Println((*s1).Name) //韩梅梅
- }
复制代码 4.4第四种方法
键值对初始化:- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- s1 := Student{
- Name: "蕾蕾",
- Number: 20250306123,
- }
- fmt.Printf("s1=%#v\n", s1) //s1=main.Student{Name:"蕾蕾", Number:20250306123}
- fmt.Println(s1.Name) //蕾蕾
- }
复制代码 4.5第五种方法
布局体指针举行键值对初始化:- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- s1 := &Student{
- Name: "蕾蕾",
- }
- fmt.Printf("s1=%#v\n", s1) //s1=&main.Student{Name:"蕾蕾", Number:0}
- fmt.Println(s1.Name) //蕾蕾
- fmt.Println((*s1).Name) //蕾蕾
- }
复制代码 留意:在创建一个布局体变量后,假如没有给字段赋值,都对应一个零值(默认值)。
布尔范例是false,数值是0,字符串是“”。
数组范例的默认值和它的元素范例干系,比如score[3]int 则为[0,0,0]。
指针,slice和map的零值都是nil,即还没有分配空间。假如须要使用如许的字段须要先make,才气使用。
4.6第六种方法
使用列表初始化,也就是初始化的时间不写键,直接写值。
留意:
- 必须初始化布局体的全部字段。
- 初始化的添补次序必须与字段在布局体中的声明次序同等。
- 该初始化不能和键值初始化方式混用。
- type Student struct {
- Name string //姓名
- Number int //学号
- }
- func main() {
- s1 := &Student{
- "蕾蕾",
- 1234567890,
- }
- fmt.Printf("s1=%#v\n", s1) //s1=&main.Student{Name:"蕾蕾", Number:1234567890}
- fmt.Println(s1.Name) //蕾蕾
- fmt.Println((*s1).Name) //蕾蕾
- }
复制代码 5.布局体的方法和吸收者
5.1布局体是值范例
- package main
- import "fmt"
- type Person struct {
- Name string
- Age int
- }
- func main() {
- p1 := Person{
- "小王子",
- 18,
- }
- p2 := p1
- p2.Name = "kings"
- fmt.Printf("%#v\n", p1) //main.Person{string:"小王子", int:18}
- fmt.Printf("%#v\n", p2) //main.Person{Name:"kings", Age:18}
- }
复制代码 在go语言中,没有类的概念但是可以给范例(布局体,自界说范例)界说方法。所谓方法 就是界说了吸收者的函数。吸收者的概念就雷同于其他语言中的this大概 self。
方法的界说格式如下:
func (吸收者变量 吸收者范例) 方法名(参数列表) (返回参数) { 函数体 }
此中
- 吸收者变量:吸收者中的参数变量名在定名时,官方发起使用吸收者范例名的第一个小 写字母,而不是self、this之类的定名。比方,Person范例的吸收者变量应该定名为 p, Connector 范例的吸收者变量应该定名为c等。
- 吸收者范例:吸收者范例和参数雷同,可以是指针范例和非指针范例。
- 方法名、参数列表、返回参数:详细格式与函数界说雷同。
给布局体Person界说一个方法打印Person的信息 :- package main
- import "fmt"
- type Person struct {
- name string
- age int8
- }
- func (p Person) printInfo() {
- fmt.Printf("姓名:%v 年龄:%v", p.name, p.age)
- }
- func main() {
- p1 := Person{
- name: "李雷",
- age: 15,
- }
- p1.printInfo() //姓名:李雷 年龄:15
- }
复制代码 对上面范例阐明:
- func (p Person) printInfo() {} 体现Person布局体有一方法,方法名为printInfo。
- (p Person)体现printInfo方法是和Person范例绑定的。
- printInfo方法只能通过Person范例的变量调用,而不能直接调用,也不能使用其他范例变量来调用。
- func (p Person) printInfo() {} p体现那么Person变量调用,这个p就是它的副本,这点和函数传参非常相似。
5.2值范例的吸收者
当方法作用于值范例吸收者时,Go语言会在代码运行时将吸收者的值复制一份。在值范例 吸收者的方法中可以获取吸收者的成员值,但修改使用只是针对副本,无法修改吸收者变量 自己。
5.3指针范例的吸收者
指针范例的吸收者由一个布局体的指针构成,由于指针的特性,调用方法时修改吸收者指针 的恣意成员变量,在方法竣过后,修改都是有效的。这种方式就非常靠近于其他语言中面向 对象中的this大概self。 - package main
- import "fmt"
- type Person struct {
- name string
- age int
- }
- // 值类型接受者
- func (p Person) printInfo() {
- fmt.Printf("姓名:%v年龄:%v\n", p.name, p.age)
- }
- // 指针类型接收者
- func (p *Person) setInfo(name string, age int) {
- p.name = name
- p.age = age
- }
- func main() {
- p1 := Person{
- name: "小王子",
- age: 25,
- }
- p1.printInfo() //姓名:小王子年龄:25
- p1.setInfo("张三", 20)
- p1.printInfo() //姓名:张三年龄:20
- }
复制代码 6.给恣意范例添加方法
在Go语言中,吸收者的范例可以是任何范例,不光仅是布局体,任何范例都可以拥有方法。 举个例子,我们基于内置的int范例使用type关键字可以界说新的自界说范例,然后为我们 的自界说范例添加方法。- package main
- import "fmt"
- type myInt int
- func (m myInt) SayHello() {
- fmt.Println("Hello,我是一个int。")
- }
- func main() {
- var m1 myInt
- m1.SayHello() //Hello,我是一个int。
- m1 = 100
- fmt.Printf("%#v %T\n", m1, m1) //100 main.MyInt
- }
复制代码 留意事项:非当地范例不能界说方法,也就是说我们不能给别的包的范例界说方法。
7.布局体的匿名字段
布局体允许其成员字段在声明时没有字段名而只有范例,这种没著名字的字段就称为匿名字 段。- import "fmt"
- type Person struct {
- string
- int
- }
- func main() {
- p1 := Person{
- "小王子",
- 18,
- }
- fmt.Printf("%#v\n", p1) //main.Person{string:"小王子", int:18}
- fmt.Println(p1.string, p1.int) //小王子 18
- }
复制代码 匿名字段默认接纳范例名作为字段名,布局体要求字段名称必须唯一,因此一个布局体中同 种范例的匿名字段只能有一个。
8.嵌套布局体
一个布局体中可以嵌套包罗另一个布局体大概布局体指针。- package main
- import "fmt"
- type Address struct {
- City string
- Phone string
- }
- type User struct {
- Name string
- Sex string
- AddressKey Address
- }
- func main() {
- user := User{
- Name: "张三",
- Sex: "男",
- AddressKey: Address{
- City: "杭州",
- Phone: "132*****321",
- },
- }
- fmt.Printf("%#v\n", user)//main.User{Name:"张三", Sex:"男", AddressKey:main.Address{City:"杭州", Phone:"132*****321"}}
- }
复制代码 9.嵌套匿名布局体
匿名布局体嵌套可以使用匿名布局体全部的方法和字段,即首字母大写或小写的字段、方法,都可以使用。- package main
- import "fmt"
- type Address struct {
- City string
- Phone string
- }
- type User struct {
- Name string
- Sex string
- Address //匿名结构体
- }
- func main() {
- user := User{
- Name: "张三",
- Sex: "男",
- Address: Address{
- City: "杭州",
- Phone: "132*****321",
- },
- }
- user.Address.City = "北京" //通过匿名结构体.字段名访问
- user.City = "上海" //直接访问匿名结构体的字段名
- fmt.Printf("%#v\n", user) //main.User{Name:"张三", Sex:"男", AddressKey:main.Address{City:"杭州", Phone:"132*****321"}}
- }
复制代码 匿名布局体字段访问可以简化:
- 当我们直接通过user访问字段或方法,实在行流程如下,比如user.city="上海"。
- 编译器会先看user对应的范例有没有City,假如有直接带哦用user范例的City字段。
- 假如没有就去user中嵌入的匿名布局体Adress中有没有声明City字段,假如有就调用,假如没有继续查找,假如找不到就报错。
- 就近查找原则,优先查找布局体中的字段或方法,假如像访问匿名布局体的字段和方法,可以通过匿名布局体名来区分。如下
- package main
- import "fmt"
- type A struct {
- Name string
- Age int
- }
- type B struct {
- Name string
- A //匿名结构体
- }
- func main() {
- b := B{}
- //就近原则,会访问B结构体的Name字段
- b.Name = "BBB"
- b.Age = 18
- //要访问你A结构体里面的Name字段,就要明确指定访问A匿名结构体的Name字段,b.A.Name
- b.A.Name = "AAA"
- fmt.Printf("%#v\n", b) // main.B{Name:"BBB", A:main.A{Name:"AAA", Age:18}}
- }
复制代码
10.嵌套匿名布局体的字段名辩说
- package main
- import (
- "fmt"
- "time"
- )
- type Address struct {
- City string
- Phone string
- CreateTime string
- }
- type Email struct {
- Acount string
- CreateTime string
- }
- type User struct {
- Name string
- Sex string
- Address //匿名结构体
- Email //匿名结构体
- }
- func main() {
- user := User{
- Name: "张三",
- Sex: "男",
- Address: Address{
- City: "杭州",
- Phone: "132*****321",
- },
- }
- user.Email.CreateTime = time.Now().Format("2006-01-02 03:04:05")//指定Email结构体中的CreateTime
- user.Address.CreateTime = time.Now().Format("2006-01-02 03:04:05")//指定Address结构体中的VreateTime
- fmt.Printf("%#v\n", user) //main.User{Name:"张三", Sex:"男", Address:main.Address{City:"杭州", Phone:"132*****321", CreateTime:"2025-03-16 05:49:43"}, Email:main.Email{Acount:"", CreateTime:"2025-03-16 05:49:43"}}
- }
复制代码 留意:嵌套布局体内大概存在雷同的字段名称,这时间为了制止歧义须要指定详细的嵌套布局体字段。
11.布局体的继续
go语言中使用布局体也可以实现其他编程语言中的继续关系,使用匿名布局体嵌套实现继续。- package main
- import "fmt"
- type Animal struct {
- Name string
- }
- func (receiver Animal) printName() {
- fmt.Println("名字:", receiver.Name)
- }
- type Dog struct {
- Color string
- Age int
- *Animal
- }
- func main() {
- dog := &Dog{}
- dog.Animal = &Animal{
- Name: "大黄",
- }
- dog.printName() //名字:大黄
- }
复制代码 12.json数据
JSON是一种轻量级的数据交换格式,易于阅读和编写,同时也易于呆板分析和天生。
json的根本格式:- {
- "avgSeatView": "4.8%",
- "avgShowView": "7.5",
- "boxRate": "58.6%",
- "boxSplitUnit": {
- "num": ".",
- "unit": "万"
- },
- "movieInfo": {
- "movieId": 1294273,
- "movieName": "哪吒之魔童闹海",
- "releaseInfo": "上映47天"
- },
- "showCount": 142769,
- "showCountRate": "36.1%",
- "splitBoxRate": "59.0%",
- "splitBoxSplitUnit": {
- "num": ".",
- "unit": "万"
- },
- "sumBoxDesc": "148.58亿",
- "sumSplitBoxDesc": "134.35亿"
- }
复制代码 13.布局体与JSON序列化
go json序列化是指把布局体数据转化成json格式的字符串,go json的反序列化是指把json数据转化成go中的布局体对象。
go中的序列化和反序列化重要通过“encoding/json”包中的json.Marshal()和json.Unmarshal()方法实现。
13.1布局体转JSON字符串
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Persion struct {
- ID int
- Sex string
- Name string
- Hobby []string
- }
- func main() {
- p := Persion{
- ID: 10001,
- Sex: "男",
- Name: "赵六",
- Hobby: []string{"篮球", "足球", "羽毛球"},
- }
- fmt.Printf("%#v\n", p) //main.Persion{ID:10001, Sex:"男", Name:"赵六", Hobby:[]string{"篮球", "足球", "羽毛球"}}
- by, err := json.Marshal(p)
- if err != nil {
- fmt.Println("转译错误!!")
- } else {
- fmt.Println(string(by)) //{"ID":10001,"Sex":"男","Name":"赵六","Hobby":["篮球","足球","羽毛球"]}
- }
- }
复制代码 13.2json字符串转换成布局体对象
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Persion struct {
- ID int
- Sex string
- Name string
- Hobby []string
- }
- func main() {
- str := `{"ID":10001,"Sex":"男","Name":"赵六","Hobby":["篮球","足球","羽毛球"]}`
- var p Persion
- err := json.Unmarshal([]byte(str), &p)
- if err != nil {
- fmt.Println("序列化错误!")
- } else {
- fmt.Printf("%#v\n", p) //main.Persion{ID:10001, Sex:"男", Name:"赵六", Hobby:[]string{"篮球", "足球", "羽毛球"}}
- }
- }
复制代码 14.布局体标签tag
Tag是布局体的元素信息,可以在运行的时间通过反射的机制读取出来。tag在布局体字段的后方界说,由一对反引号包裹起来,详细格式如下:
`key1:"value1" key2:"value2"`
布局体tag由一个或多个键值构成。键与值使用冒号分隔,值用双引号括起来。同一个布局体字段可以设置多个键值对tag,差异的键值对之间使用空格分隔。
留意事项:为布局体编写tag时,必须严酷服从键值对的规则。布局体标签的分析代码的容错本事很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法精确取值,列如不要在key和value之间添加空格。
14.布局体转json字符串
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Persion struct {
- ID int `json:"id"` //通过指定tag实现json序列化该字段时key(id)
- Sex string `json:"sex"`
- Name string `json:"name"`
- Hobby []string `json:"hobby"`
- }
- func main() {
- p := Persion{
- ID: 10001,
- Sex: "男",
- Name: "赵六",
- Hobby: []string{"篮球", "足球", "羽毛球"},
- }
- by, err := json.Marshal(p)
- if err != nil {
- fmt.Println("转译错误!!")
- } else {
- fmt.Println(string(by)) // {"id":10001,"sex":"男","name":"赵六","hobby":["篮球","足球","羽毛球"]}
- }
- }
-
复制代码 14.2json字符串转化成布局体
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Persion struct {
- ID int `json:"id"` //通过指定tag实现json序列化该字段时key(id)
- Sex string `json:"sex"`
- Name string `json:"name"`
- Hobby []string `json:"hobby"`
- }
- func main() {
- str := `{"id":10001,"sex":"男","name":"赵六","hobby":["篮球","足球","羽毛球"]}`
- var p Persion
- err := json.Unmarshal([]byte(str), &p)
- if err != nil {
- fmt.Println("序列化错误!")
- } else {
- fmt.Printf("%#v\n", p) //main.Persion{ID:10001, Sex:"男", Name:"赵六", Hobby:[]string{"篮球", "足球", "羽毛球"}}
- }
- }
复制代码 15.嵌套布局体和json序列化反序列化
15.1布局体转化成json字符串
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type Student struct {
- ID int `json:"id"` //通过指定tag实现json序列化该字段时key(id)
- Sex string `json:"sex"`
- Name string `json:"name"`
- Hobby []string `json:"hobby"`
- }
- type Class struct {
- No string `json:"no"`
- Student []Student `json:"student"`
- }
- func main() {
- var cl Class
- cl.No = "六年级一班"
- stu := make([]Student, 0)
- for i := 0; i < 10; i++ {
- s := Student{
- ID: 1000 + i,
- Sex: "男",
- Name: fmt.Sprintf("王五%v", i),
- Hobby: []string{"java", "php", "golang"},
- }
- stu = append(stu, s)
- }
- cl.Student = stu
- by, err := json.Marshal(cl)
- if err != nil {
- fmt.Println("转译错误!")
- } else {
- fmt.Println(string(by))
- }
- }
复制代码 效果:- {"no":"六年级一班","student":[{"id":1000,"sex":"男","name":"王五0","hobby":["java","php","golang"]},{"id":1001,"sex":"男","name":"王五1","hobby":["java","php","golang"]},{"id":1002,"sex":"男","name":"王五2","hobby":["java","php","golang"]},{"id":1003,"sex":"男","name":"王五3","hobby":["java","php","golang"]},{"id":1004,"sex":"男","name":"王五4","hobby":["java","php","golang"]},{"id":1005,"sex":"男","name":"王五5","hobby":["java","php","golang"]},{"id":1006,"sex":"男","name":"王五6","hobby":["java","php","golang"]},{"id":1007,"sex":"男","name":"王五7","hobby":["java","php","golang"]},{"id":1008,"sex":"男","name":"王五8","hobby":["java","php","golang"]},{"id":1009,"sex":"男","name":"王五9","hobby":["java","php","golang"]}]}
复制代码 15.2json字符串转化成布局体
- package mainimport ( "encoding/json" "fmt")type Student struct { ID int `json:"id"` //通过指定tag实现json序列化该字段时key(id) Sex string `json:"sex"` Name string `json:"name"` Hobby []string `json:"hobby"`}type Class struct { No string `json:"no"` Student []Student `json:"student"`}func main() { str := `
- {"no":"六年级一班","student":[{"id":1000,"sex":"男","name":"王五0","hobby":["java","php","golang"]},{"id":1001,"sex":"男","name":"王五1","hobby":["java","php","golang"]},{"id":1002,"sex":"男","name":"王五2","hobby":["java","php","golang"]},{"id":1003,"sex":"男","name":"王五3","hobby":["java","php","golang"]},{"id":1004,"sex":"男","name":"王五4","hobby":["java","php","golang"]},{"id":1005,"sex":"男","name":"王五5","hobby":["java","php","golang"]},{"id":1006,"sex":"男","name":"王五6","hobby":["java","php","golang"]},{"id":1007,"sex":"男","name":"王五7","hobby":["java","php","golang"]},{"id":1008,"sex":"男","name":"王五8","hobby":["java","php","golang"]},{"id":1009,"sex":"男","name":"王五9","hobby":["java","php","golang"]}]}
- ` var cl Class err := json.Unmarshal([]byte(str), &cl) if err != nil { fmt.Println("序列化错误!") } else { fmt.Printf("%#v", cl) }}
复制代码 效果:- main.Class{No:"六年级一班", Student:[]main.Student{main.Student{ID:1000, Sex:"男", Name:"王五0", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1001, Sex:"男", Name:"王五1", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1002, Sex:"男", Name:"王五2", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1003, Sex:"男", Name:"王五3", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1004, Sex:"男", Name:"王五4", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1005, Sex:"男", Name:"王五5", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1006, Sex:"男", Name:"王五6", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1007, Sex:"男", Name:"王五7", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1008, Sex:"男", Name:"王五8", Hobby:[]string{"java", "php", "golang"}}, main.Student{ID:1009, Sex:"男", Name:"王五9", Hobby:[]string{"java", "php", "golang"}}}}
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |