struct

面向对象编程

  • Go支持面向对象编程特性,但和传统面向对象编程是有区别的,Go并不是纯粹的面向对象语言。
  • Go没有类,其结构体和其它编程语言中的类具有同等的地位,可理解Go是基于结构体来实现面向对象特性的。
  • Go面向对象编程非常简介,去掉了传统面向对象语言的继承、方法重载、构造函数、析构函数、隐藏的this指针等。
  • Go仍然具有面向对象编程的继承、封装、多态的特性,只是实现方式和传统面向对象语言不同。
  • Go面向对象很优雅,面向对象本身就是语言类型系统的一部分,通过接口关联,耦合性低,也非常灵活。
  • Go中面向接口编程是非常重要的特性

结构体与结构体变量

  • 结构体:自定义的数据类型,表示一类事物。
type struct_name struct {
  field1 datatype
  field2 datatype
}

//定义结构体
type User struct {
    Id     int
    Name   string
    Birth  string
    Gender int
}
  • 结构体变量:又称为实例或对象,是具体的、实际的,代表一个具体变量。

//结构体变量
var u User
u.Id = 1
u.Name = "alice"
u.Birth = "2020-12-21"
u.Gender = 1

结构体字段

  • 结构体字段又称为属性,字段是结构体组成部分,一般是基础数据类型、数组,也可以是引用类型。
  • 字段声明语法同变量一样采用字段名 字段类型
  • 字段类型可分为:基本类型、数组、引用类型
  • 创建结构体变量后若没有给字段赋值,都会对应一个零值作为默认值。
  • 不同结构体变量的字段是独立互不影响,一个结构体变量的更改不会影响到另外一个,因为结构体是值类型默认是值拷贝。
字段类型 类型 零值
布尔类型 基础 false
整型 基础 0
字符串 基础 ""
数组类型 基础 默认值与元素类型相关
指针ptr/切片slice/映射map 引用 nil,未分配空间。

结构体字段类型若存在指针、slicemap,它们的零值都是nil,即还没有分配空间,如果需要使用必须先make()

类型 创建
指针 new()
切片 make()
映射 make()
//定义结构体
type User struct {
    Id    int
    array [5]float64
    slice []int
    ptr   *int
    dict  map[string]string
}

//结构体变量
var u User
fmt.Printf("%+v\n", u)             // {Id:0 array:[0 0 0 0 0] slice:[] ptr:<nil> dict:map[]}
fmt.Printf("%t\n", u.slice == nil) //true
fmt.Printf("%t\n", u.ptr == nil)   //true
fmt.Printf("%t\n", u.dict == nil)  //true

创建结构体变量

//创建结构体变量
var u1 User             //直接声明
fmt.Printf("%+v\n", u1) //{Id:0}

var u2 User = User{}
fmt.Printf("%+v\n", u2) //{Id:0}

采用结构体指针方式创建后,结构体指针访问字段的标准方式应该是 (*结构体指针).字段名,但Go做了简化也支持结构体指针.字段名,因为这种方式更加符合程序员的使用习惯。Go编译器底层会对简化方式做自动转换。

var u3 *User = new(User)
fmt.Printf("%+v\n", u3) //&{Id:0}

var u4 *User = &User{}
fmt.Printf("%+v\n", u4) //&{Id:0}

简化写法

var u *User = new(User)
fmt.Printf("%+v\n", u) //&{Id:0}

(*u).Id = 100
fmt.Printf("%+v\n", *u)

u.Id = 200
fmt.Println(u)

由于u是一个指针,因此标准的给字段赋值的方式应该采用的是(*u).Id = 100,但也可以直接采用u.Id = 200。由于Go设计者为了程序员使用方便,底层会对u.Id = 200添加取值运算。

创建结构体实例时可直接指定字段的值

type User struct {
    Id   int
    Name string
}

func main() {
    u := User{1, "alice"}
    fmt.Printf("%+v\n", u) // {Id:1 Name:alice}
}

内存分配机制

例如:结构体是值类型,默认赋值会拷贝副本,若需采用引用类型方式,则需使用结构体变量指针赋值。

u1 := User{1}
u2 := &u1 // var u2 *User = &u1
u2.Id = 100
fmt.Printf("%+v\n", u1)               // {Id:100}
fmt.Printf("%+v\n", u2)               // &{Id:100}
fmt.Printf("u1=%p, u2=%p\n", &u1, u2) // u1=0xc0000aa058, u2=0xc0000aa058

.点运算符优先级要高于*星号运算符,下列为错误写法:

u1 := User{1}
u2 := &u1 // var u2 *User = &u1
u2.Id = 100
fmt.Printf("%+v\n", *u2.Id) // invalid indirect of u2.Id (type int) (exit status 2)

注意事项

结构体字段在内存中是连续分布的

type Point struct {
    x, y int
}
type Rect struct {
    leftUp, rightDown Point
}

func main() {
    r := Rect{
        Point{0, 0},
        Point{4, 4},
    }
    fmt.Printf("%p\n", &r.leftUp.x)    // 0xc0000a8080
    fmt.Printf("%p\n", &r.leftUp.y)    // 0xc0000a8088
    fmt.Printf("%p\n", &r.rightDown.x) // 0xc0000a8090
    fmt.Printf("%p\n", &r.rightDown.y) // 0xc0000a8098
}

指针本身的地址是连续但指向的地址不一定是连续的

type Point struct {
    x, y int
}
type Rect struct {
    leftUp, rightDown *Point
}

func main() {
    r := Rect{
        &Point{0, 0},
        &Point{4, 4},
    }
    fmt.Printf("%p\n", &r.leftUp)    // 0xc000088220
    fmt.Printf("%p\n", &r.rightDown) // 0xc000088228

    fmt.Printf("%p\n", r.leftUp)    // 0xc0000aa070
    fmt.Printf("%p\n", r.rightDown) // 0xc0000aa080

}

结构体是用户单独定义的类型,和其它类型进行转换时需具有完全相同的字段(名字、个数、类型)。

type Point struct {
    x, y int
}
type Axis struct {
    x, y int
}

func main() {
    p1 := Point{0, 0}
    p2 := Axis(p1)
    fmt.Printf("%+v\n", p1) // {x:0 y:0}
    fmt.Printf("%+v\n", p2) // {x:0 y:0}
}

结构体进行type重新定义时相当于取别名,Go会认为是新的数据类型,但相互之间可以强转。

type Point struct {
    x, y int
}
type Axis Point

func main() {
    var p1 Point
    var p2 Axis

    //p1 = p2 //  cannot use p2 (type Axis) as type Point in assignment (exit status 2)

    p1 = Point(p2)
    fmt.Printf("%+v %+v\n", p1, p2) // {x:0 y:0} {x:0 y:0}
}

结构体字段上可添加一个标签tag,标签可通过反射机制获取,比如序列化和反序列化中。

type Response struct {
    Code int         `json:"code"`
    Msg  string      `json:"msg`
    Data interface{} `json:"data"`
}

func main() {
    response := Response{200, "success", nil}
    buf, err := json.Marshal(response)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Printf("%s\n", buf) // {"code":200,"Msg":"success","data":null}
}

工厂模式

Go的结构体没有构造函数,可通过工厂模式来实例化结构体。

// 结构体
type user struct {
    Id   int
    Name string
}

// 工厂模式
func User(id int, name string) *user {
    return &user{
        Id:   id,
        Name: name,
    }
}

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

推荐阅读更多精彩内容