1.1.1. 一、Golang 语言面向对象编程说明。

  • Golang 也支持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以我们说 Golang 支持面向对象编程特性是比较准确的。
  • Golang 没有类(class),Go 语言的结构体(struct)和其它编程语言的类(class)有同等的地位,你可以理解 Golang 是基于 struct 来实现 OOP 特性的。
  • Golang 面向对象编程非常简洁,去掉了传统 OOP 语言的方法重载、构造函数和析构函数、隐藏的 this 指针等等。

  • Golang 仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它 OOP 语言不一样,比如继承 :Golang 没有 extends 关键字,继承是通过匿名字段来实现。

  • Golang 面向对象(OOP)很优雅,OOP 本身就是语言类型系统(type system)的一部分,通过接口 (interface)关联,耦合性低,也非常灵活。也就是说在 Golang 中面向接口编程是非常重要的特性。

1.1.2. 二、struct的定义和使用。

定义struct的语法:

type 结构体名 struct {
    属性名1 类型
    属性名2 类型
    // 其他属性和方法
}

1、如果结构体的名字首字母大写,其他包可以使用这个结构体。

2、如果结构体内的属性名首字母大写,表示这个属性可以在其他包使用。

示例如下:

// 定义一个结构体,名字叫Person
type Person struct {
    Name string
    age int
    Height float32
}
func main() {
    // 声明一个Person类型变量
    var p1 Person

    // 没有赋值默认零值
    fmt.Println(p1) // { 0 0}

    // 属性赋值
    p1.Name = "张三"
    p1.age = 18
    p1.Height = 1.9
    fmt.Println(p1) //{张三 18 1.9}
    //取出属性值
    fmt.Println(p1.Name,p1.age,p1.Height) //张三 18 1.9
}

说明:

  1. 结构体的属性名,首字母大写,相当于其他语法的public。表示这个属性可以在其他包使用。
  2. 声明结构体变量时,结构体内的属性会被赋予默认值(零值)。如果是指针,slice,和 map 的零值都是 nil ,即还没有分配空间。指针,slice,和 map 使用时要先make(类似于new),否则报错。

1.1.3. 三、结构体是值类型。传递是值传递。

例子如下:p1是结构体,p2 := p1 //这里是值传递。相当于拷贝了一份。改变p2的属性值,并不能改变p1的属性值。

// 定义一个结构体,名字叫Person
type Person struct {
    Name string
    age int
}
func main() {
    // 声明一个Person类型变量
    var p1  = Person{"张三",18}

    p2 := p1 //这里是值传递。相当于拷贝了一份。

    p2.Name = "p2李四"

    fmt.Println(p1.Name) // 张三
    fmt.Println(p2.Name) // p2李四
}

1.1.4. 四、创建结构体变量的4种方式。

下面例子中的结构体Person:

type Person struct {
    Name string
    age int
}

1、直接声明:var p1 Person

func main() {
    var p1 Person
    p1.Name = "张三"
    p1.age = 18
    fmt.Println(p1)
}

2、用大括号。p3 := Person{}

func main() {
    var (
        p1  = Person{"张三",18} // 顺序赋值全部属性。类型为 Person
        p2 = Person{Name:"李四"} //只赋值Name属性
        p3 = Person{}// 不赋值任何属性
        p4Point  = &Person{"王5", 2} // 类型为Person指针 *Person
    )
    // {张三 18} {李四 0} { 0} &{王5 2}
    fmt.Println(p1, p2, p3, p4Point)
}

3、声明结构体的指针。

  • var p1Point = &Person{"王5", 22}
  • var p2Point = new(Person)
func main() {
    var p1Point  = &Person{"王5", 22} // 类型为Person指针 *Person
    var p2Point  = new(Person) // 类型为Person指针 *Person
    //给指针指向的Person赋值
    (*p2Point).Name = "拉登" // 简化为:p2Point.Name = "拉登"

    fmt.Println(p1Point) // &{王5 2}
    fmt.Println(p2Point) // &{拉登 0}
    //查询值
    p1Age := (*p1Point).age // 简化为:p1Age := p1Point.age
    fmt.Println(p1Age) //22
}

说明:

因为go语言的底层做了处理,所以上面的Person指针对属性的修改、查询可以简化如下:

(*p2Point).Name = "拉登" 简化为 p2Point.Name= "拉登"

p1Age := (*p1Point).age 简化为 p1Age := p1Point.age

1.1.5. 五、结构体的注意事项。

1、结构体的所有字段在内存中是连续的

也就是结构体中属性变量本身的地址,是连续分配的。

2、结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的属性(名字、个数和类 型)。

也就是如果把一个结构体的实例强制转换为另一个类型的结构体,需要他们的属性完全相同(属性名字、个数和类 型)。否则编译报错,不能强制转换。

type A struct {
    Name string
}
type B struct {
    Name string
}
func main() {
    var a  = A{"张三"}
    b := B(a) //强制转换为B类型
    fmt.Println(b)// {张三}
}

3、结构体进行 type 重新定义(相当于取别名),Golang 认为是新的数据类型,但是相互间可以强转。

type Student struct {
    Name string
}
type B Student //B类型是新的数据类型,只是和Student类型有相同的结构

func main() {
    var stu  = Student{"张三"}
    //var b1 B = stu 编译报错,B类型是新的数据类型。不能直接赋值。
    b := B(stu) //可以强制转换为B类型
    fmt.Println(b)// {张三}
}

4、struct 的每个字段上,可以写上一个 tag, 该 tag 可以通过反射机制获取,常见的使用场景就是序列化和反序列化。

示例:在属性类型后面加个字符串。这个字符串就是tag。

type Student struct {
    Name string `json:"ageTest"` //`json:"age"` 就是tag
    Age int `json:"age"`
    Sex string `json:"sex"`
}

func main() {
    var stu  = Student{"张三",20,"男"}

    // json.Marshal() 函数使用反射读取tag,把stu转换为json。
    str,err := json.Marshal(stu)
    if err != nil {
        fmt.Println("json转换错误")
    }else {
        ////如果tag是这种格式 json:"age" ,后面的age就是对应的json字符串的属性名
        // 转换json后: {"ageTest":"张三","age":20,"sex":"男"}
        fmt.Println("转换json后:",string(str))
    }
}

results matching ""

    No results matching ""