go结构体指针 | 青训营

59 阅读5分钟

结构体

Go语言中没有像C++ Java等 “类”的概念,也不支持“类”的继承,多态等面向对象的特征(不是纯oop的语言)。但是Go语言可以通过结构体和接口的使用实现比向对象具有更高的扩展性和灵活性的功能。

类型别名和自定义类型

自定义类型

除了Go语言基本的数据类型string、整型、浮点型、布尔等数据类型, 我们可以通过type关键词 自定义类型。

类型别名

类型别名是一个类型的别称,本质上还是同一个类型。

type 原神=int

常见的rune,byte,any就是类型别名

// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8

// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32

// any is an alias for interface{} and is equivalent to interface{} in all ways.
type any = interface{}

结构体

结构体的定义

使用typestruct关键字来定义结构体:

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

结构体实例

只有当结构体实例化时,才会真正地分配内存。也就是必须实例化后才能使用结构体的字段。 结合前面所说 结构体本身也是一种类型,我们可以像声明内置类型一样使用var关键字声明结构体类型 或者是**:=**语法糖(匿名结构体)。

匿名结构体

在以后的 学习过程中 匿名结构体也经常出现在全局变量管理 模板渲染 数据测试 等

//var
var 原神 struct{Name string; Age int} ; 原神.Name = "genshin" ; 原神.Age = 3

//推荐
原神 := struct {
		Name string
		Age int
	}{
		"genshin",
		3,
	}

结构体的访问

我们通过上述 代码可以轻而易举的知道 给以直接拿到整个结构体变量 但是我们应该怎么获取结构体的成员呢?

我们可以通过 . 操作来进行访问。

  a := struct {
		Name string
		Age int
	}{
		"yuan1",
		18,
	}

fmt.Println(a)
fmt.Println(a.Name)
fmt.Println(a.Age)

但并不是所有的成员函数都可以访问

在Go中 没有public、protected、private等访问控制修饰符,它是通过字母大小写来控制可见性的,如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头表示能被其它包访问或调用(相当于public),非大写开头就只能在包内使用(相当于private,变量或常量也可以下划线开头)

嵌套结构体

我们把一个结构体中可以嵌套包含另一个结构体或结构体指针 叫做 嵌套结构体或者是结构体内嵌

type People struct {
    Name string
    Age  int
}

type Banked struct {
    Name string
    member People 
}

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self。 方法的定义格式如下:

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

指针

区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针

要搞明白Go语言中的指针需要先知道3个概念:指针地址指针类型指针取值

Go语言中的指针

go语言中的函数传参都是值传递,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。

具体可以 看看go语言中的函数传参都是值传递

指针地址和指针类型

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行“取地址”操作。 Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string

我们可以通过 **&**来获取 地址

 ptr := &v    // v的类型为

举个例子

func main() {
    a := 10
    b := &a
    fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
    fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
    fmt.Println(&b)                    // 0xc00000e018
}

空指针

  • 当一个指针被定义后没有分配到任何变量时,它的值为 nil

  • 空指针的判断

package main

import "fmt"

func main() {
   var p *string
   fmt.Println(p)
   fmt.Printf("p的值是%v\n", p)
   if p != nil {
       fmt.Println("非空")
   } else {
       fmt.Println("空值")
   }
}

new和make

new

new是一个内置的函数,它的函数签名如下:

func new(Type) *Type

make

make也是用于内存分配的,区别于new,它只用于slicemap以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。make函数的函数签名如下:

func make(t Type, size ...IntegerType) Type