go-基础补充与struct类型

在前面几篇博文中记录了Go中一些基础语法,接下来补充记录一下一些基础使用以及struct类型类型的使用:

基础补充

import导包

我们知道,导入一个包,我们只需要使用import "xxx"即可,导入多个包我们可以使用:

import (
    "package1",
    "package2"
)

我们还可以这样:

import . "fmt"

接下来,我们就可以不适用包名来调用函数了,如下:

package main
import . "fmt"

func main(){
    Println("import . fmt的使用")
}

执行程序将会打印如下内容:

import . fmt的使用

我们还可以为包起个别名,如下:

import io "fmt"

如此,我们就为fmt包起了个别名叫做io。起别名的作用是什么呢?有可能我们会遇到两个名字一模一样的包,但是功能不一样,我们都需要使用,此时,我们就可以为其起一个别名来进行区分!

我们知道,当我们导入一个包时,就必须使用这个包,如果未曾使用它,那么将会发生变异错误!此时,我们可以使用_,来进行忽略它:

import _ "fmt"

有人会想,这样写有什么用,你直接删除不就行了,何必这样大费周章!其实,这样写法,除了可以忽略这个包,但是它还会执行这个包的init函数,当有需要只需要执行它的init函数时,你就可以使用这种写法!

init函数

Go里面有两个保留的函数:init函数和main函数。这两个函数不能有任何的参数和返回值。每个包可以包含任意多个init函数,这些函数都会在程序执行开始的时候被调用。所有被编译器发现的init函数都会安排在main函数之前执行。假设有这样一个目录结构:

|Demo
|--models/
|----model.go
|--main.go

model.go代码如下:

package models
import "fmt"

func init(){
    fmt.Println("models-model中的init函数")
}

func init(){
    fmt.Println("models-model中的init函数-2")
}

func Sum(a, b int) (result int) {
    result = a + b
    return
}

main.go代码如下:

package main
import (
    "Demo/models",
    "fmt"
)

func init(){
    fmt.Println("这是main中的init函数")
}

func main(){
    result := models.Sum(10, 20)
    fmt.Println(result)
}

接下来,我们运行一下main.go文件,将会打印如下信息:

models-model中的init函数
models-model中的init函数-2
这是main中的init函数
30

首先,程序会先去找了import里面中导入包中去寻找init函数,然后依次执行,然后执行当前main包中的init函数,最后执行main函数的内容!

new函数

表达式new(T)将创建一个T类型的匿名变量,所做的是为T类型的新值分配并清零一块内存空间,然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的T类型值的指针值,返回的指针类型为*T:

package main
import "fmt"

func main() {
    var a1 *int
    a1 = new(int)
    fmt.Println(*a1)
    
    
    a2 := new(int)
    *a2 = 20
    fmt.Println(*a2)
}

// 打印结果如下
0
20

我们还可以这样来使用:

package main
import "fmt"

func main() {
    var a1 = 20
    
    a2 := new(int)
    a2 = &a1
    *a2 = 18
    
    fmt.Println(a1, *a2)         // 20 20
}

我们只需要使用new()函数,无需担心其内存的生命周期或怎么样将其删除,因为Go语言的内存管理系统会帮我们打理一切!

struct类型

Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其他类型的属性或字段的容器。例如,我们可以创建一个自定义类型Student来代表一个学生的实体。这个实体拥有属性:名称、年龄和地址信息。这样的类型我们称之为struct,如下代码所示:

type Student struct{
    name string
    age int
    addr string
}

接下来,我们来进行使用它:

var s Student
s.name = "laozhang"
s.age = 18
s.addr = "广东深圳"

fmt.Println(s)

// 打印结果如下
{laozhang 18 广东深圳}

除了上面这种声明使用之外,struct类型还有几种声明使用方式:

  • 按照顺序提供初始值
s := Student{"laozhang", 18, "广东深圳"}
  • 根据field:value方式初始化,这样可以任意顺序
s := Student{age: 18, name: "laozhang", addr: "广东深圳"}
  • 当然,也可以通过new函数来分配一个指针,下面的s为指针类型
s := new(Student)
s.name = "laozhang"
s.age = 18
s.addr = "广东深圳"

fmt.Println(*s)

// 打印结果如下
{laozhang 18 广东}

值得注意的是,按照顺序提供初始值,需要多有struct下的所有属性进行赋值,否则将会报错,其他方式不需要,未进行赋值的属性将默认会是零值!

值得注意的是,如果struct类型作为形参传递给另外一个函数,并在该函数修改struct类型的内容,原struct类型的值是不会发生改变的,如下:

package main
import "fmt"

type Student struct{
    name string
    age int
    addr string
}

func modify(s Student){
    s.age = 20
}

func main(){
    s := Student{"laozhang", 10, "广东深圳"}
    modify(s)
    
    fmt.Println(s)
}

// 打印结果如下
{laozhang 10 广东深圳}

观察结果发现,源struct类型的值并未发生改变。如果你有这样一个需求,需要在其他函数改变它的值,并使源struct类型生效,你可以传递一个指针,如下:

package main
import "fmt"

type Student struct{
    name string
    age int
    addr string
}

func modify(s *Student){
    s.age = 20
    
    // 或者使用下面这种写法,效果都是一样的
    // (*s).age = 20
}

func main(){
    s := Student{"laozhang", 18, "广东深圳"}
    modify(&s)
    
    fmt.Println(s)
}

struct匿名字段

实际上Go还支持只写类型,不写字段名称的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct类型时,那么这个struct所拥有的所有字段都被隐式的引入了当前定义的这个struct。举个栗子:

package main
import "fmt"

type People struct{
    name string
    age int
    addr string
}
type Student struct{
    People
    score int
}

func main(){
    var s Student
    s.name = "laozhang"
    s.age = 18
    s.addr = "广东深圳"
    s.score = 98
    
    fmt.Println(s)
}

// 打印结果如下
{{laozhang 18 广东深圳} 98}

包含匿名字段的struct类型,也可以使用上面初始化方式,如下:

  • 按顺序提供初始值
s := Student{People{"laozhang", 18, "广东深圳"}, 98}
  • 根据field:value方式初始化,这样可以任意顺序
s := Student{People: People{"laozhang", 18, "广东深圳"}, score: 98}
  • 当然,也可以通过new函数来分配一个指针,下面的s为指针类型
s := new(Student)
s.name = "laozhang"
s.age = 18
s.addr = "广东深圳"
s.score = 98

fmt.Println(*s)

// 打印结果如下
{{laozhang 18 广东深圳} 98}

值得注意的是,如果当包含匿名字段时,本身字段名称与匿名字段中的属性名称有相同时,我们再进行.语法赋值时,只会给当前的struct类型的属性进行赋值,如下:

package main
import "fmt"

type People struct{
    name string 
    age int
    addr string
}
type Student struct{
    People
    name string
}

func main(){
    var s Student
    s.name = "laozhang"
    s.age = 18
    s.addr = "广东深圳"
    
    fmt.Println(s)
}

// 打印结果如下
{{ 18 广东深圳} laozhang}

观察结果可以得知,匿名字段中的name属性并未成功赋值,而是给予的是一个零值。那么要如何才能给这种字段名称相同的情况下赋值呢,我们可以这样:

var s Student
s.People.name = "laozhang"
s.age = 18
s.addr = "广东深圳"
s.name = "laowang"

又或者这样:

var s Student
s.People = People{"laozhang", 18, "广东深圳"}
s.name = "laowang"

至此,Over~~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值