go面向对象(结构体)

结构体

  • 一个程序就是一个世界,有很多对象(变量)


  • 思路
    1、用变量解决
    2、用数组解决

使用变量和数组来解决不利于数据的维护。所以引出用结构体来抽象猫的特性。

Golang语言面向对象编程说明

1、golang也支持面向对象(OOP),但是和传统的面向对象编程有区别。并不是纯粹的面向对象。应该说。Golang支持面向对象特性。
2、Golang没有类(class),Go语言的结构体(struct)和其它语方的类(class)有同等的地位,你可以理解Golang是基于struct来实现OOP特性。
3、Golang面向对象非常简洁,去掉了传统OOP语言的继承,方法重载,构造函数,析构函数、隐藏的this指针
4、Golang仍然有面向对象编程的继承,封装和多态特性。只是实现的方式和其它不一样。比如继承:Golang没有extends关键字,继承是通过匿名字段来实现的。
5、Golang面向对象(OOP)很优雅。OOP本身就是语方类型(type stystem)的一部分。通过接口(interface)关联。耦合性低,Golang中面向接口编程是非常重要的特性。

对上图的说明
1、将一类事物的特性提取出来(比如猫类),形成一个新的数据类型(结构体)。
2、通过结构体,可以创建多个变量(实例)
3、事物可以猫类,人类,或某个工具类。

  • 快速入门解决(面向对象解决养猫的问题)
//定义结构体
type Cat struct {
    Name  string //""
    Age   int    // 0
    Color string // ""
    Hobby string
}

func main() {
    //创建一个cat的变量
    var cat1 Cat
    fmt.Println(cat1)
    cat1.Name = "小白"
    cat1.Age = 3
    cat1.Color = "白色"
    cat1.Hobby = "吃鱼 <*(((()->"
    fmt.Println(cat1)
    fmt.Println("猫名:", cat1.Name)
    fmt.Println("猫年龄:", cat1.Age)
    fmt.Println("猫颜色:", cat1.Color)
    fmt.Println("猫喜欢:", cat1.Hobby)
}

通过上面案例可以看出
1、结构体是自定义的数据类型,代表一类事物
2、结构体变量(实例)是具体的,实际的,代表一个具体变量。

结构体变量在内存中的布局。

结构体声明

type 结构体名称 struct {
    字段  字段类型
    Age   int    // 0
    Color string // ""
    Hobby string
//首字母大写是公有的,可以被其它包使用
}

字段/属性注意及说明

1、字段声明语法同变量,字段名 字段类型
2、字段的类型可为:基本类型、数组或引用类型
3、在创建一个结构体充数量后。如果没有赋值,都对应一个零值

布尔类型是false,数值是0,字符串是""
数组类型的默认值和它的元素类型相关,比如 scope [3]int 默认值 是[0,0,0]
指针,slice,和map的零值是nil,即还没有分配内存空间

//定义结构体
type Person struct {
    Name   string //""
    Age    int    // 0
    Scores [5]float64
    Ptr    *int              //指针
    Slice  []int             //切片
    Map1   map[string]string //map

}
func main() {
    //定义结构体变量
    var p1 Person
    fmt.Println(p1)
    if p1.Ptr == nil {
        fmt.Println("ok1")
    }
    if p1.Slice == nil {
        fmt.Println("ok2")
    }
    if p1.Map1 == nil {
        fmt.Println("ok3")
    }

    //先make再赋值
    p1.Slice = make([]int, 10)
    p1.Slice[0] = 100
    fmt.Println(p1)

    p1.Map1 = make(map[string]string)
    p1.Map1["key1"] = "tom~~"
    fmt.Println(p1)
}

4、不同结构体的变量的字段是独立的,互不影响。

//定义结构体
type Monster struct {
    Name string
    Age  int
}

func main() {
    //定义结构体变量
    var monster1 Monster
    monster1.Name = "牛魔王"
    monster1.Age = 500

    monster2 := monster1 //默认结构体是值类型,默认为值拷贝
    monster2.Name = "青牛精"
    fmt.Println("monster1=", monster1)
    fmt.Println("monster2=", monster2)
}

上面代码的内存示意图


创建结构体变量和访问结构体字段 4种方式

1、方式1- 直接声明

//案例:
var person Person

2、方式2- { }

//定义结构体
type Monster struct {
    Name string
    Age  int
}

func main() {
    //定义结构体变量
    p2 := Monster{"mary", 20}
    //p2.Name = "tom"
    fmt.Println(p2)
}

3、方式3 - 通过new

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    //方式3
    var p3 *Person = new(Person)
    //因为祝p3是一个指针,标准方式是
    //(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"
    //为了方便使用,会在底层做了处理
    //会给 p3加上 取值运算  (*p3).Name = "smith"
    (*p3).Name = "smith"
    p3.Name = "john"
    (*p3).Age = 30
    p3.Age = 99
    fmt.Println(*p3)
}

4、方式4 - &{ }

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    //方式3
    var p3 *Person = new(Person)
    //因为祝p3是一个指针,标准方式是
    //(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"
    //为了方便使用,会在底层做了处理
    //会给 p3加上 取值运算  (*p3).Name = "smith"
    (*p3).Name = "smith"
    p3.Name = "john"
    (*p3).Age = 30
    p3.Age = 99
    fmt.Println(*p3)

    //方式4 - &name{}
    var person *Person = &Person{}
    //创建的时候赋值
    //var person *Person = &Person{"mary",60}

    //因为person是一个指针,因此标准的用法是
    //(*person).Name = "scott"
    //但是为了简化,go的设计者为了程序员方便,也可以直接这样用
    //person.Name = "scott"
    (*person).Name = "scott"
    person.Name = "scott~~~"
    (*person).Age = 88
    person.Age = 111

    fmt.Println(*person)
}

说明:

1、第3种和第4种方式返回的都是结构体的指针
2、结构体指针访问字段的标准方式是 结构体指针.字段名,比如:
(*person).Name = "tom"
3、但是go做了简化,它也支持 结构体名.字段名,因为go在编译器层做了转化处理。

struct类型的内存分配机制

  • 变量总是存在内存中的。

结构体的变量在内存中是如何存在的,看下面图示

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    var p1 Person
    p1.Age = 10
    p1.Name = "小明"

    var p2 *Person = &p1

    fmt.Println((*p2).Age)
    fmt.Println(p2.Age)

    p2.Name = "tom~"
    fmt.Printf("p2.Name = %v p1.Name = %v \n", p2.Name, p1.Name)
    fmt.Printf("p2.Name = %v p1.Name = %v \n", (*p2).Name, p1.Name)

    fmt.Printf("p1的地址:%p\n", &p1)

    fmt.Printf("p2的值为:%p\n", p2)
    fmt.Printf("p2的地址:%p\n", &p2)
}

注意

fmt.Println(*p2.Age) 写法会报错。原因是:.的优先级比*高,
所以用()括起来。()优先级大于.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容