Go语言从入门到精通三——struct和interface_Dev-L的博客-CSDN博客_go interface struct

Go中的struct

struct用来自定义复杂数据结构,相当于其他面向对象语言中的Class。

  • struct里面可以包含多个字段(属性)
  • struct类型可以自定义方法,注意和函数的区分:方法有一个接受对象,而函数没有
  • struct类型是值类型
  • struct类型可以嵌套
  • Go语言没有class类型,只有struct类型

struct声明

语法:
type 标识符 struct{
field1 type
field2 type
}
如:

type Student struct{
    Name string 
    Age int
    Score int
}

struct定义的三种形式

var stu Student
var stu *Student = new(Student)
var stu *Student = &Student{}

其中,后两种返回的都是指向结构体的指针,访问形式如下:
stu.Namestu.Agestu.Score或者 (*stu).Name(*stu).Age(*stu).Score

struct的内存布局

struct中的所有字段在内存是连续的,布局如下:
在这里插入图片描述

struct工厂模式

golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题。

package model

import "fmt"

type student struct {
    name string
    age int
}

func NewStudent(name string, age int) *student {
    return &student{
        name: name,
        age:  age,
    }
}

func (s student)Print()  {
    fmt.Println(s.name, s.age)
}
package main

import (
    "golang_learning/model"
    "fmt"
    "strings"
)

func main() {
    s := model.NewStudent("sam", 18)
    s.Print()
    fmt.Println(strings.Repeat("*", 10))
}

struct中的tag

我们可以为struct中的每个字段,写上一个tag。这个tag可以通过反射的机制获取到,最常用的场景就是json序列化和反序列化。

type student struct {
    Name string  "this is name field"
    Age int      "this is age field"
}

还有一种场景是,由于golang中的字段大写才能导出,到与其他语言交互时,字段名多为小写,这个时候也可以使用tag来解决。

type student struct {
    Name string  "name"
    Age int      "age"
}

struct中的匿名字段

type Wheel struct {
    Name string
    Size int
}

type Car struct {
    Wheel
    Comp string
    Date time.Time
    int
}

字段冲突的处理

只要冲突的字段不再同一个级别,就不会panic;可以通过明确指定来访问。

type Wheel struct {
    Name string
    Size int
}

type Car struct {
    Wheel
    Comp string
    Date time.Time
    Size int
}
    w := Wheel{"w", 1}
    c := Car{w, "auto", time.Now(), 20}
    fmt.Println("%v", w)
    fmt.Println("%v", c)
    fmt.Println(c.Size)
    fmt.Println(c.Wheel.Size)
    // 20
    // 1

golang中的方法

Golang中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct。如:

package main

import (
    "fmt"
)

type Int int

func (i Int)print()  {
    fmt.Println(i)
}

func main() {
    i := Int(99)
    i.print()
}
// 99

定义:func (recevier type) methodName(参数列表)(返回值列表){}
另外,方法的访问控制,通过大小写控制。

方法和函数的区别:

  • 函数调用: function(variable, 参数列表)
  • 方法:variable.function(参数列表)

指针receiver vs 值receiver

结构体是值类型的,如果需要修改其内部的值,需要使用指针。

继承和组合

模拟继承

如果一个struct嵌套了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的方法,从而实现了继承。

多重继承

如果一个struct嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的方法,从而实现了多重继承。

组合

如果一个struct嵌套了另一个有名结构体,那么这个模式就叫组合。

String()方法

如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个
变量的String()进行输出。

package main

import (
    "fmt"
    "strconv"
)

type student struct{
    name string
    age int
}

func (s student)String() string{
    return "name: " + s.name + ", age: " + strconv.Itoa(s.age)
}
func main() {
    s := student{"lee", 18}
    fmt.Println(s)
    fmt.Printf("%s", s)
}
//  name: lee, age: 18
//  name: lee, age: 18

接口

Interface类型可以定义一组方法,但是这些不需要实现。并且interface不能
包含任何变量。

接口的定义

interface类型默认是一个指针

type example interface{

        Method1(参数列表) 返回值列表
        Method2(参数列表) 返回值列表
        ...
}
var a example
a.Method1()

接口实现

  • golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字
  • 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口
  • 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口

多态

一种事物的多种形态,都可以按照统一的接口进行操作

接口嵌套

一个接口可以嵌套在另外的接口,比如:

type ReadWrite interface {
    Read(b int) bool
    Write(b int) bool
}
type Lock interface {
    Lock()
    Unlock()
}
type File interface {
    ReadWrite
    Lock
    Close()
}

类型断言

由于接口是一般类型,不知道其具体类型,如果要转换成具体类型,可以使用下面的方法进行转换:

var t int
var x interface{}
x = t
y, ok := x.(int)   // 转成int
func classifier(items ...interface{}) {
    for i, x := range items {
        switch x.(type) {
        case bool:
            fmt.Printf("param #%d is a bool\n", i)
        case float64:
            fmt.Printf("param #%d is a float64\n", i)
        case int, int64:
            fmt.Printf("param #%d is an int\n", i)
        case nil:
            fmt.Printf("param #%d is nil\n", i)
        case string:
            fmt.Printf("param #%d is a string\n", i)
        default:
            fmt.Printf("param #%d’s type is unknown\n", i)
        }
    }
}

空接口

空接口没有任何方法,所以所有类型都实现了空接口。

var a int
var b interface{}
b = a

判断一个变量是否实现了指定接口

type Stringer interface {
    String() string
}

var v MyStruct
if sv, ok := v.(Stringer); ok {
    fmt.Printf("v implements String():%s\n", sv.String())
}

变量slice和接口slice之间赋值操作

变量slice和接口slice之间赋值操作,应该使用for range

    var a []int
    var b []interface{}
    // b = a   //error!!!
    for index, value := range a{
        b[index] = value
    }
    fmt.Println(b)

原网址: 访问
创建于: 2022-08-18 13:39:07
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论