Golang-结构体


  Golang支持面向对象编程(OOP),但是和传统的面向对象编程(Java)又有区别,所以只能说 Golang是支持面向对象编程特性

  传统的面向对象编程是怎么样?
  拿Java作为例子,定义一个Person类,里面包含了这个Person的一些属性或特征。

public class Person(){
    private String name;
    
    private int age;
    
    private String addr;
}

然后根据这个类来创建对象来进行使用。

既然Golang是支持面向对象编程特性,那是使用什么来实现OOP呢?

那就是结构体struct

先展示一个struct的样子。

//定义一个Dog的结构体,将Dog的各个字段或属性信息,放入Dog结构体进行管理
type Dog struct {
    name string
    age int
    addr string
}

  这时候就不难发现,struct和Java的class的结构是差不多的,那golang的结构体是怎么进行管理的?

//创建一个Dog的变量
var dogo Dog
dogo.name = "小黄"
dogo.age = 2
dogo.addr = "home"

fmt.Println("狗狗的个人简历如下:")
fmt.Println("name=", dogo.name)
fmt.Println("name=", dogo.age)
fmt.Println("name=", dogo.addr)

结合上面的描述,

  1. 结构体是自定义的数据类型,代表一类事物。(Dog)
  2. 结构体变量(实例)是具体的,实际的,代表一个具体变量。(dogo)

结束了对比,现在来正式介绍Golang的结构体(struct)

声明结构体

  1. 语法结构
type 结构体名称 struct {
    field1 type //字段属性
    field2 type
    ...
}

具体例子上面有描述,这里就不赘述了。

  1. 字段属性

  字段是结构体的一个重要组成部分,一般是基本数据类型、数组,也可以是引用类型

type Person struct{
    name string
    age int
    scores [3]float64 //数组
    ptr *int //指针
    slice []int //切片
    mapp map[string]string //map
}

//如果结构体的字段类型是:指针,slice和map的零值都是nil,表示还没有分配空间
//如果要使用,就要先make,才能使用。

func main(){
    var per Person
    
    //使用slice ,一定要先用make
    per.slice = make([]int, 5)
    per.slice[0] = 3
    
    //使用map,一定要先用make
    per.mapp = make(map[string]string)
    per.mapp["key"] = "aaa"
    
    fmt.Println(per)
}
  1. 字段的独立性

  不同结构体变量(实例)的字段是独立的,互不影响,一个实例的字段改变了,不影响另外一个实例。

type Dog struct {
    name string
    age int
}


func main(){
    //不同实例的字段互不影响
    var dog1 Dog
    dog1.name = "小黄"
    dog1.age = 1
    
    dog2 := dog1 //结构体是值类型,默认是值拷贝
    dog2.name = "小白"
    
    fmt.Println("dog1=",dog1) //dog1 = {小黄 1},dog1的name没有受到影响
    fmt.Println("dog2=",dog2) //dog2 = {小白 1}
}

创建与访问

  在结构体声明后,就要去创建使用,对于结构体的创建使用主要有几个方式:
  这里取Dog的结构体为例

type Dog struct {
    name string
    age int
}
//方式一:
//这个方式就是最基础的直接声明
type doge Dog

//方式二:
doge := Dog{"小黄", 2}

//方式三:
var doge *Dog = new(Dog)

(*doge).name = "aa" //因为doge是一个指针,所以标准的赋值方式
doge.name = "bb" //不过这种方式也支持,因为在底层有对doge.name = "bb"进行处理

(*doge).age = 2
doge.age = 3
fmt.Println(*doge) //返回结构体的指针

//方式四:
var doge *Dog = &Dog{}

(*doge).name = "aa"
doge.name = "bb"

(*doge).age = 2
doge.age = 3
fmt.Println(*doge) //返回结构体的指针

方法

  在一些场景下,结构体单单只是属性是不够的,比如像Person结构体除了要有一些属性(name,age),还需要有一些行为:可以说话、奔跑这些,所以这时候结构体就要用到方法。

  golang中的方法是作用在指定的数据类型上的(和指定的数据类型绑定),所以自定义类型都可以有方法,不单单是struct。

  1. 方法的声明和调用
type C struct{
    num int
}

func (c C) test(){
    fmt.Println(c.num)
}


这段例子表示:
1. func(c C) test(){}  表示C结构体有一个方法名叫做test()
2. (c C)表示test()方法是和C类型绑定的

具体的例子说明

type Dog struct {
    name string
    age int
}

func(d Dog) say(){
    fmt.Println("say() name = ", d.name)
}

func main(){
    var d Dog
    d.name = "啊黄"
    d.say()  // 调用方法
}

上面的代码体现出来几个点:

  1. say方法和Dog类型绑定。
  2. say方法只能通过Dog类型的变量来调用,不能直接调用,也不能使用其他类型变量进行调用。
  3. func(d Dog) say(){}中的d表示哪个Dog变量调用。

方法也可以接收参数,比如

func (d Dog) say(n int){
    for i := 1; i<= n; i++{
        fmt.Println("第%d次叫",i)    
    }
}

//调用
d.say(2)

方法也可以返回参数,比如

func (d Dog) cout(n int) int {
    res := 0
    for i := 1; i<= n; i++ {
        res += 1    
    }
    return res
}

//调用
res := d.cout(5)
  1. 使用方法需要注意

(1) 结构体类型是值类型,在方法调用中,要遵守值类型的传递机制,是值拷贝传递方式

(2) 若想在方法中修改结构体变量的值,可以通过结构体的指针来处理。

//为了提高效率,通常将方法和结构体的指针类型绑定
func (d *Dog) cout() int {
    retrun 2
}

//调用
res := d.cout() //等同于res := (&d).cout() ,只是底层做了优化

(3) golang中的方法作用在指定的数据类型上的(也就是和指定的数据类型绑定),所以自定义类型都可以拥有方法,不单单是struct,还可以是int ,float64都可以拥有方法。

func (i integer) print() {
    fmt.Println("i=", i)
}

func (i *integer) change(){
    *i = *i + 1
}

func main(){
    var i integer = 10
    i.print()
    i.change()
    fmt.Println("i=", i)
}

(4) 方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。

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

type Student struct {
    name string
    age int
}

//给*Student实现方法String()
func (stu *Student) String() string {
    str := fmt.Sprintf("name=[%v] age=[%v]", stu.name, stu.age)
    return str
}

//定义一个Student变量
stu := Student{
    name : "jam"
    age : 10
}
//如果实现了*Student 类型的String方法,就会自动调用
fmt.Println(&stu)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是哈猿啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值