zoukankan      html  css  js  c++  java
  • Golang语言学习笔记(九)

    Golang中的复合数据类型

    4.结构体

    1).关于Golang结构体

    Golang中没有类的概念,Golang中的结构体和其他语言中的类有点相似。和其他面向对象语言中的类相比,Golang中的结构体具有更高的扩展性和灵活性

    Golang中的基础数据类型可以表示一些事物的基本属性,但是当我们想表达一个事物的全部或部分属性时,再使用但是的基本数据类型就无法满足需求了,Golang中提供了一种自定义数据类型,可以封装多个基本数据类型,这种数据类型叫结构体,英文名称struct。我们可以通过struct来定义自己的类型。

    2).Golang type关键字自定义类型和类型别名

    Golang中通过type关键字定义一个结构体

    自定义类型
    在Go语言中有一些基本的数据类型,如string、整型、浮点型、布尔等数据类型,Go语言中可以使用type关键字来定义自定义类型。

    type myInt int
    

    上面代码表示:将myInt定义为int类型,通过type关键字的定义,myInt就是一种新的类型,它具有int的特性。

    类型别名
    Golang1.9版本以后添加的新功能
    类型别名规定:TypeAlias只是Type的别名,本质是TypeAlias与Type是同一个类型。

    type TypeAlias = Type
    

    3).结构体定义初始化的几种方法

    结构体的定义
    使用type和struct关键字来定义结构体,具体代码格式如下:

    type 类型名 struct {
        字段名 字段类型
        字段名 字段类型
        ...
    }
    

    其中

    • 类型名:表示自定义结构体的名称,在同一个包内不能重复
    • 字段名:表示结构体字段名,结构体中的字段名必须唯一
    • 字段类型:表示结构体字段的具体类型

    结构体实例化(第一种方法)
    只有当结构体实例化时,才会真正的分配内存,也就是必须实例化后才能使用结构体的字段。
    结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型

    var 结构体实例 结构体类型
    

    结构体实例化(第二种方法)
    我们还可以通过使用new关键字对结构体进行实例化,得到的是结构体的地址

    var 结构体实例 = new(结构体类型)
    
    var p2 = new(Person)
    p2.name = "lisi"
    p2.age = 20
    p2.sex = "Male"
    

    注意:在Golang中支持对结构体指针直接使用.来访问结构体的成员。p2.name = "lisi" 其实在底层是(*p2).name = "lisi"

    结构体实例化(第三种方法)
    使用&对结构体进行取地址操作相当于对该结构体类型进行了一次new实例化操作

    结构体实例化(第四种方法)
    键值对初始化

    var 结构体实例 = 结构体类型{
    	结构体属性: 属性对应值,
    	结构体属性: 属性对应值,
    	...
    }
    

    注意,最后一个属性的逗号(,)要加上

    结构体实例化(第五种方法)
    结构体指针进行键值对初始化

    var 结构体实例 = &结构体类型{
    	结构体属性: 属性对应值,
    	结构体属性: 属性对应值,
    	...
    }
    

    当某些字段没有初始值的时候,这个字段可以不写。此时,没有指定初始值的字段的值为类型零值

    结构体实例化(第六种方法)
    使用值的列表初始化
    初始化结构体的时候可以简写,也就是初始化的时候不写键,直接写值:

    结构体实例 := &结构体类型{
        属性值,
        属性值,
        ...
    }
    

    4).结构体方法和接收者

    在Go语言中给,没有类的概念但是可以给类型(结构体,自定义类型)定义方法。所谓方法就是定义了接收这的函数。接收者的概念就类似于其他语言中的this或者self。
    方法的定义格式如下:

    func (接收者变量 接收者类型) 方法名(参数列表)(返回参数){
        函数体
    }
    

    其中

    • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名的第一个小写字母,而不是self、this之类的命名。列如,Person类型的接收者变量应该命名为p,Connector类型的接收者变量名应该命名为c等。
    • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
    • 方法名、参数列表、返回参数:具体格式与函数定义相同。

    5).给任意类型添加方法

    在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。

    6).结构体的匿名字段

    结构体允许其成员变量在声明是没有字段名只有类型,这种没有字段名字的字段就称为匿名字段

    7).嵌套结构体

    结构体的字段类型可以是:基本数据类型,也可以是切片、map 以及结构体
    如果结构体的字段类型是:指针、slice、和map的零值都是nil,即还没有分配空间
    如果需要使用这样的字段,就要先make,才能使用

    8).嵌套匿名结构体

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

    9).关于嵌套结构体的字段名冲突

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

    10).结构体的继承

    Go语言中使用结构体也可以实现其他编程语言中的继承
    一个结构体中可以嵌套包含另一个结构体或者结构体指针

    Golang结构体和Json相互转换 序列化 反序列化

    1.关于JSON数据

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。RESTful API 接口中返回的数据都是json数据

    2.结构体与JSON序列化

    如果Golang要给App或者小程序提供API接口数据,就需要涉及到结构体和json之间的相互转换

    Golang JSON序列化是指把结构体数据转化成JSON格式的字符串,Golang JSON 的反序列化是指把JSON数据转化成Golang中的结构体对象

    Golang中的序列化和反序列化主要通过"encoding/json"包中的json.Marshal()和json.Unmarshal()方法实现。

    3.结构体标签Tag

    Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:

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

    结构体tag由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。同一个结构体字段可以设置多个键值对tag,不同的键值对之间使用空格分隔。

    注意事项:为结构体编写tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误信息,通过反射也无法正确取值。例如不要再key和value之间添加空格。

    4.嵌套结构体和JSON序列化反序列化

    4.关于Map、切片的序列化反序列化

    Map和切片也可以进行序列化和反序列化,在学习接口之后再详细学习。

    代码:

    package main
    
    import (
    	"fmt"
            "encoding/json"
    )
    
    //自定义类型
    type MyInt int
    
    //注意:非本地类型不能定义方法,也就是不能给别的包的类型定义方法
    func (m MyInt) PrintInfo() {
    	fmt.Println("我是自定义类型的自定义方法")
    }
    
    type myFn func(int, int) int
    
    //类型别名
    type myFloat = float64
    
    //注意:结构体首字母可以大写也可以小写,大写表示这个结构体是公有的,在其他的包里面可以使用,小写表示这个结构体是私有的,只有这个包里面才能使用
    type Person struct {
    	name string
    	age  int
    	sex  string
    }
    
    func (p Person) PrintInfo() {
    	fmt.Printf("name:%v, age:%v", p.name, p.age)
    }
    
    //想要修改结构体的属性值,接收体类型必须是结构体指针
    func (p *Person) SetInfo(name string, age int) {
    	p.name = name
    	p.age = age
    }
    
    type Student struct {
    	name string
    	age  int
    	sex  string
    }
    
    /*
    	结构体的匿名字段:
    
    		结构体允许其成员变量在声明是没有字段名只有类型,这种没有字段名字的字段就称为匿名字段
    
    		匿名字段默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个
    
    */
    type Teacher struct {
    	string
    	int
    }
    
    /*
    	嵌套结构体
    
    	结构体的字段类型可以是:基本数据类型,也可以是切片、map 以及结构体
    	如果结构体的字段类型是:指针、slice和map的零值都是nil,即还没有分配空间
    	如果需要使用这样的字段,就要先make,才能使用
    */
    type Driver struct {
    	Name  string
    	Age   int
    	Hobby []string
    	map1  map[string]string
    }
    
    type User struct {
    	Username string
    	Password string
    	Address  Address //User结构体嵌套Address结构体
    }
    
    type Address struct {
    	Name  string
    	Phone string
    	City  string
    }
    
    /*
    	嵌套匿名结构体
    */
    type Customer struct {
    	Username string
    	Password string
    	Address
    }
    
    //嵌套结构体的字段名冲突
    
    type Client struct {
    	Username string
    	Password string
    	Addtime string
    	Contact
    }
    
    type Contact struct {
    	Name  string
    	Phone string
    	City  string
    	Addtime string
    }
    
    type Employee struct {
    	Username string
    	Password string
    	Contact
    	Email
    }
    
    type Email struct {
    	Account string
    	Addtime string
    }
    
    
    //结构体的继承
    //一个结构体中可以嵌套包含另一个结构体或者结构体指针
    
    //父结构体
    type Animal struct {
    	Name string
    }
    
    func (a Animal) run(){
    	fmt.Printf("%v 在运动
    ", a.Name)
    }
    
    //子结构体
    type Dog struct{
    	Age string
    	Animal //结构体嵌套 继承
    }
    
    func (d Dog) shout(){
    	fmt.Printf("%v 在旺旺
    ", d.Name)
    }
    
    type Cat struct{
    	Age string
    	*Animal //结构体嵌套 继承
    }
    
    func (c Cat) shout(){
    	fmt.Printf("%v 在旺旺
    ", c.Name)
    }
    
    //json序列化
    type Professor struct {
    	ID     int    `json:"id"` //通过指定tag实现json序列化该字段时的key
    	Gender string `json:"gender"`
    	// name string//私有属性不能被json包访问
    	Name string `json:"name"`
    	Pno  string `json:"pno"`
    }
    
    type Learner struct {
    	Id     int
    	Gender string
    	Name   string
    }
    
    type Class struct {
    	Title    string
    	Learners []Learner
    }
    
    func main() {
    
    	//结构体
    
    	//类型别名
    	// var a myInt = 10
    	// fmt.Printf("%v %T
    ", a, a)//10 main.myInt
    
    	// var b myFloat = 10.3
    	// fmt.Printf("%v %T
    ", b, b)//10。3 float64
    
    	//
    	// var p1 Person //实例化Person结构体
    	// p1.name = "zhangsan"
    	// p1.age = 20
    	// p1.sex = "Male"
    	// fmt.Printf("值:%v  类型:%T
    ", p1, p1)//值:{zhangsan 20 Male}  类型:main.Person
    	// //使用%#v打印结构体具体信息
    	// fmt.Printf("值:%#v  类型:%T", p1, p1)//值:main.Person{name:"zhangsan", age:20, sex:"Male"}  类型:main.Person
    
    	//注意:在Golang中支持对结构体指针直接使用.来访问结构体的成员。p2.name = "lisi" 其实在底层是(*p2).name = "lisi"
    	// var p2 = new(Person)
    	// p2.name = "lisi"
    	// p2.age = 20
    	// p2.sex = "Male"
    	// fmt.Printf("值:%#v  类型:%T
    ", p2, p2)//值:&main.Person{name:"lisi", age:20, sex:"Male"}  类型:*main.Person
    
    	// (*p2).name = "wangwu"
    	// fmt.Printf("值:%#v  类型:%T
    ", p2, p2)//值:&main.Person{name:"wangwu", age:20, sex:"Male"}  类型:*main.Person
    
    	// var p3 = &Person{}
    	// p3.name = "zhaoliu"
    	// p3.age = 23
    	// p3.sex = "Male"
    	// fmt.Printf("值:%#v  类型:%T
    ", p3, p3) //值:&main.Person{name:"zhaoliu", age:23, sex:"Male"}  类型:*main.Person
    
    	// var p4 = Person{
    	// 	name: "test",
    	// 	age:  20,
    	// 	sex:  "Female",
    	// }
    	// fmt.Printf("值:%#v  类型:%T
    ", p4, p4)//值:main.Person{name:"test", age:20, sex:"Female"}  类型:main.Person
    
    	// var p5 = &Person{
    	// 	name: "Tom",
    	// 	age:  20,
    	// 	sex:  "Female",
    	// }
    	// fmt.Printf("值:%#v  类型:%T
    ", p5, p5)//值:&main.Person{name:"Tom", age:20, sex:"Female"}  类型:*main.Person
    
    	// var p6 = &Person{
    	// 	name: "Jerry",
    	// }
    	// fmt.Printf("值:%#v  类型:%T
    ", p6, p6)//值:&main.Person{name:"Jerry", age:0, sex:""}  类型:*main.Person
    
    	// var p7 = &Person{
    	// 	"hana",
    	// 	25,
    	// 	"Female",
    	// }
    	// fmt.Printf("值:%#v  类型:%T
    ", p7, p7)//值:&main.Person{name:"hana", age:25, sex:"Female"}  类型:*main.Person
    
    	//结构体方法和接收者
    
    	// var s1 = Student {
    	// 	name: "ash",
    	// 	age:  27,
    	// 	sex:  "Female",
    	// }
    
    	// s2 := s1
    	// s2.name = "hana"
    	// fmt.Printf("%#v
    ",s1)//main.Student{name:"ash", age:27, sex:"Female"}
    	// fmt.Printf("%#v
    ",s2)//main.Student{name:"hana", age:27, sex:"Female"}
    	// //结构体是值类型
    
    	// var p = Person{
    	// 	name: "zhangsan",
    	// 	age: 20,
    	// 	sex: "Male",
    	// }
    	// p.PrintInfo()//name:zhangsan, age:20
    	// fmt.Println()
    
    	// var pp = Person{
    	// 	name: "lisi",
    	// 	age: 20,
    	// 	sex: "Male",
    	// }
    	// pp.PrintInfo()//name:lisi, age:20
    	// fmt.Println()
    	// p.PrintInfo()//name:zhangsan, age:20
    
    	//Golang中结构体实例是独立的,不会相互影响
    	// fmt.Println()
    	// p.SetInfo("wangwu",11)
    	// p.PrintInfo()//name:wangwu, age:11
    	// fmt.Println()
    	// pp.PrintInfo()//name:lisi, age:20
    
    	// var myInt MyInt
    	// myInt.PrintInfo()
    
    	//匿名结构体
    	// t := Teacher {
    	// 	"zhangsan",
    	// 	30,
    	// }
    
    	// fmt.Println(t)//{zhangsan 30}
    
    	//嵌套结构体
    	// var d Driver
    	// d.Name = "lisi"
    	// d.Age = 30
    	// d.Hobby = make([]string, 3, 6)
    	// d.Hobby[0] = "drive"
    	// d.Hobby[1] = "sport"
    	// d.Hobby[2] = "sleep"
    
    	// d.map1 = make(map[string]string)
    	// d.map1["address"] = "beijing"
    	// d.map1["phone"] = "12345678901"
    
    	// // fmt.Printf("%#v",d)//main.Driver{Name:"lisi", Age:30, Hobby:[]string{"drive", "sport", "sleep"}, map1:map[string]string{"address":"beijing", "phone":"12345678901"}}
    
    	// fmt.Printf("%v", d.Hobby) //[drive sport sleep]
    
    	// var u User
    	// u.Username = "hana"
    	// u.Password = "123456"
    	// u.Address.Name = "zhangsan"
    	// u.Address.Phone = "12343879609"
    	// u.Address.City = "chengdu"
    
    	// fmt.Printf("%#v", u)//main.User{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"chengdu"}}
    
    	//嵌套匿名结构体
    
    	// var c Customer
    	// c.Username = "hana"
    	// c.Password = "123456"
    	// c.Address.Name = "zhangsan"
    	// c.Address.Phone = "12343879609"
    	// c.Address.City = "chengdu"
    
    	// // fmt.Printf("%#v
    ", c)//main.Customer{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"chengdu"}}
    
    	// c.City = "ShangHai"//当访问结构体成员时,会先在结构体中查找该字段,找不到再去匿名结构体中查找。
    	// fmt.Printf("%#v
    ", c)//main.Customer{Username:"hana", Password:"123456", Address:main.Address{Name:"zhangsan", Phone:"12343879609", City:"ShangHai"}}
    
    	// fmt.Println(c.Address.Phone)//12343879609
    	// fmt.Println(c.Phone)//12343879609
    
    	//关于嵌套结构体的字段名冲突
    	// var c Client
    	// c.Username = "wangwu"
    	// c.Password = "123456"
    	// c.Contact.Name = "zhangsan"
    	// c.Contact.Phone = "12343879609"
    	// c.Contact.City = "chengdu"
    
    	// c.City = "ShenZhen"
    	// c.Addtime = "2020-10-09"
    	// fmt.Printf("%#v
    ", c)//main.Client{Username:"wangwu", Password:"123456", Addtime:"2020-10-09", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShenZhen", Addtime:""}}
    
    	// c.Contact.Addtime = "2020-10-10"
    	// fmt.Printf("%#v
    ", c)//main.Client{Username:"wangwu", Password:"123456", Addtime:"2020-10-09", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShenZhen", Addtime:"2020-10-10"}}
    
    	// var e Employee
    	
    	// e.Username = "wangwu"
    	// e.Password = "123456"
    	// e.Contact.Name = "zhangsan"
    	// e.Contact.Phone = "12343879609"
    	// e.Contact.City = "chengdu"
    
    	// e.City = "ShangHai"
    
    	// // e.Addtime = "2020-10-09"//ambiguous selector e.Addtime
    	// e.Contact.Addtime = "2020-10-09"
    	// e.Email.Addtime = "2020-10-10"
    	// fmt.Printf("%#v
    ", e)//main.Employee{Username:"wangwu", Password:"123456", Contact:main.Contact{Name:"zhangsan", Phone:"12343879609", City:"ShangHai", Addtime:"2020-10-09"}, Email:main.Email{Account:"", Addtime:"2020-10-10"}}
    
    	// var d = Dog{
    	// 	Age: "20",
    	// 	Animal: Animal{
    	// 		Name: "daqing",
    	// 	},
    	// }
    
    	// d.run()//daqing 在运动
    	// d.shout()//daqing 在旺旺
    
    
    	var c = Cat{
    		Age: "20",
    		Animal: &Animal{
    			Name: "weiwei",
    		},
    	}
    
    	c.run()//weiwei 在运动
    	c.shout()//weiwei 在旺旺
    
    
    	//结构体转json
    	// var p1 = Professor{
    	// 	ID: 11,
    	// 	Gender: "Male",
    	// 	Name: "Tom",
    	// 	Pno: "p0001",
    	// }
    
    	// fmt.Printf("%#v
    ",p1)//main.Professor{ID:11, Gender:"Male", Name:"Tom", Pno:"p0001"}
    
    	// var jsonByte, _ = json.Marshal(p1)
    	// jsonStr := string(jsonByte)
    	// fmt.Printf("%v",jsonStr)//{"ID":11,"Gender":"Male","Name":"Tom","Pno":"p0001"}
    
    	//json转结构体
    	// var str = `{"ID":11,"Gender":"Male","Name":"Tom","Pno":"p0001"}`
    	// var p2 Professor
    
    	// err := json.Unmarshal([]byte(str), &p2)
    	// if err != nil {
    	// 	fmt.Println(err)
    	// }
    
    	// fmt.Printf("%#v
    ", p2) //main.Professor{ID:11, Gender:"Male", Name:"Tom", Pno:"p0001"}
    	// fmt.Println(p2.Name)    //Tom
    
    	//结构体标签
    	// var p3 = Professor{
    	// 	ID: 11,
    	// 	Gender: "Male",
    	// 	Name: "Tom",
    	// 	Pno: "p0001",
    	// }
    
    	// var jsonByte, _ = json.Marshal(p3)
    	// jsonStr := string(jsonByte)
    	// fmt.Printf("%v",jsonStr)//{"id":11,"gender":"Male","name":"Tom","pno":"p0001"}
    
    	//嵌套结构体和JSON序列化反序列化
    	// c := Class{
    	// 	Title:    "001",
    	// 	Learners: make([]Learner, 0, 200),
    	// }
    
    	// for i := 0; i < 10; i++ {
    	// 	l := Learner{
    	// 		Id:     i,
    	// 		Gender: "Male",
    	// 		Name:   fmt.Sprintf("learn_%v", i),
    	// 	}
    
    	// 	c.Learners = append(c.Learners, l)
    	// }
    
    	// fmt.Printf("%#v
    ", c) //main.Class{Title:"001", Learners:[]main.Learner{main.Learner{Id:0, Gender:"Male", Name:"learn_0"}, main.Learner{Id:1, Gender:"Male", Name:"learn_1"}, main.Learner{Id:2, Gender:"Male", Name:"learn_2"}, main.Learner{Id:3, Gender:"Male", Name:"learn_3"}, main.Learner{Id:4, Gender:"Male", Name:"learn_4"}, main.Learner{Id:5, Gender:"Male", Name:"learn_5"}, main.Learner{Id:6, Gender:"Male", Name:"learn_6"}, main.Learner{Id:7, Gender:"Male", Name:"learn_7"}, main.Learner{Id:8, Gender:"Male", Name:"learn_8"}, main.Learner{Id:9, Gender:"Male", Name:"learn_9"}}}
    
    	// strByte, err := json.Marshal(c)
    	// if err != nil {
    	// 	fmt.Println(err)
    	// } else {
    	// 	strJson := string(strByte)
    	// 	fmt.Println(strJson)//{"Title":"001","Learners":[{"Id":0,"Gender":"Male","Name":"learn_0"},{"Id":1,"Gender":"Male","Name":"learn_1"},{"Id":2,"Gender":"Male","Name":"learn_2"},{"Id":3,"Gender":"Male","Name":"learn_3"},{"Id":4,"Gender":"Male","Name":"learn_4"},{"Id":5,"Gender":"Male","Name":"learn_5"},{"Id":6,"Gender":"Male","Name":"learn_6"},{"Id":7,"Gender":"Male","Name":"learn_7"},{"Id":8,"Gender":"Male","Name":"learn_8"},{"Id":9,"Gender":"Male","Name":"learn_9"}]}
    	// }
    
    	str := `{"Title":"001","Learners":[{"Id":0,"Gender":"Male","Name":"learn_0"},{"Id":1,"Gender":"Male","Name":"learn_1"},{"Id":2,"Gender":"Male","Name":"learn_2"},{"Id":3,"Gender":"Male","Name":"learn_3"},{"Id":4,"Gender":"Male","Name":"learn_4"},{"Id":5,"Gender":"Male","Name":"learn_5"},{"Id":6,"Gender":"Male","Name":"learn_6"},{"Id":7,"Gender":"Male","Name":"learn_7"},{"Id":8,"Gender":"Male","Name":"learn_8"},{"Id":9,"Gender":"Male","Name":"learn_9"}]}`
    
    	var c = &Class{}
    	err := json.Unmarshal([]byte(str),c)
    	if err != nil {
    		fmt.Println(err)
    	} else {
    		fmt.Printf("%#v
    ",c)//&main.Class{Title:"001", Learners:[]main.Learner{main.Learner{Id:0, Gender:"Male", Name:"learn_0"}, main.Learner{Id:1, Gender:"Male", Name:"learn_1"}, main.Learner{Id:2, Gender:"Male", Name:"learn_2"}, main.Learner{Id:3, Gender:"Male", Name:"learn_3"}, main.Learner{Id:4, Gender:"Male", Name:"learn_4"}, main.Learner{Id:5, Gender:"Male", Name:"learn_5"}, main.Learner{Id:6, Gender:"Male", Name:"learn_6"}, main.Learner{Id:7, Gender:"Male", Name:"learn_7"}, main.Learner{Id:8, Gender:"Male", Name:"learn_8"}, main.Learner{Id:9, Gender:"Male", Name:"learn_9"}}}
    
    		fmt.Println(c.Title)//001
    	}
    
    }
    
  • 相关阅读:
    let与const的区别
    IOS客户端UIwebview下web页面闪屏问题
    移动端click事件延迟300ms问题
    css3+visbibilty解决淡入淡出问题
    git学习之branch分支
    git学习之冲突解决办法
    webpack+vue-cli项目打包技巧
    一个高级PHP工程师所应该具备的
    多站点
    PHP error_reporting() 错误控制函数功能详解
  • 原文地址:https://www.cnblogs.com/hanajiang/p/13787229.html
Copyright © 2011-2022 走看看