Golang:struct定义与试用以及内存分析

概述

Golang虽然具有OOP的特性,但是并没有类的概念,也没有继承关键字。

提供了一个类似于类功能,但是又截然不同的概念:结构体struct。

定义

有四种定义方式:

package main

import "fmt"

//struct定义
type Person struct {
	Id   int64
	Name string
	Age  int8
}

type Student struct {
	baseInfo Person
	ptr      *int //指针
	array    [2]int
	slice    []int
	map1     map[string]int
}

func changePerson(p Person) {
	p.Name = "Lydia"
}

func main() {
	//struct的四种声明方式
	//方式一:直接声明
	var s Student
	fmt.Println("s=", s)

	//方式二:类型推断+初始化
	pp := Person{Id: 20001, Name: "LeoLee", Age: 26}
	s1 := Student{baseInfo: pp}
	fmt.Println("s1=", s1)

	//方式三:内建函数new,返回结构体指针
	var s2 *Student = new(Student)
	//赋值方法:获取指针的值(*s2),然后再进行赋值
	(*s2).baseInfo = pp
	//为了方便程序员,golang的作者也允许如下写法,隐式的对指针s2进行取值运算(*),再进行赋值。属于语法糖
	s2.array[0] = 1
	s2.array[1] = 2
	fmt.Printf("s2=%v, s2 type=%T\n", s2, s2)

	//方式四:使用&符,返回结构体指针
	var s3 *Student = &Student{baseInfo: pp}
	(*s3).array[0] = 1
	fmt.Printf("s3=%v, s3 type=%T\n", s3, s3)
}

struct初始化完成后,各个属性为其类型的默认值:

package main

import "fmt"

//struct定义
type Person struct {
	Id   int64
	Name string
	Age  int8
}

func main() {
	//定义Person类型的变量stu1
	var p1 Person
	fmt.Printf("p1.Id=%d,p1.Name=%s,p1.Age=%d\n", p1.Id, p1.Name, p1.Age) //初始化变量完成后,各个字段为类型的默认值
	p1.Id = int64(1000)
	p1.Name = "LeoLee"
	p1.Age = 26
	fmt.Printf("p1.Id=%d,p1.Name=%s,p1.Age=%d\n", p1.Id, p1.Name, p1.Age)
}

复杂结构体示例

package main

import "fmt"

//struct定义
type Person struct {
	Id   int64
	Name string
	Age  int8
}

type Student struct {
	baseInfo Person
	ptr      *int //指针
	array    [2]int
	slice    []int
	map1     map[string]int
}

func main() {
	var stu1 Student
	fmt.Println(stu1)
	//prt、slice、map都为nil,prt是因为没有指向内存,slice和map是因为没有make
	if stu1.ptr == nil {
		fmt.Printf("stu1.ptr=%v\n", stu1.ptr)
		//指针类型赋值
		i := 8
		stu1.ptr = &i
		fmt.Printf("stu1.ptr[%p], value=%d\n", stu1.ptr, *stu1.ptr)
	}
	if stu1.slice == nil {
		fmt.Printf("stu1.slice=%v\n", stu1.slice)
		//初始化slice
		stu1.slice = make([]int, 2)
		stu1.slice[0] = 1
		stu1.slice[1] = 2
		stu1.slice = append(stu1.slice, 3)
	}
	if stu1.map1 == nil {
		fmt.Printf("stu1.map1=%v\n", stu1.map1)
		//初始化map
		stu1.map1 = make(map[string]int)
		stu1.map1["A"] = 5
		stu1.map1["B"] = 6
	}
	stu1.baseInfo.Name = "LeoLee"
	fmt.Println(stu1)
}

引用传递

package main

import "fmt"

//struct定义
type Person struct {
	Id   int64
	Name string
	Age  int8
}

func changePerson(p Person) {
	p.Name = "Lydia"
}

func main() {
    var p1 Person
	p1.Id = int64(1000)
	p1.Name = "LeoLee"
	p1.Age = 26
	//struct是值传递类型,函数内的修改无法影响函数外的值。
	//需要进行指针才可以改变原有变量的数据
	changePerson(p1)
	fmt.Printf("p1.Id=%d,p1.Name=%s,p1.Age=%d\n", p1.Id, p1.Name, p1.Age)
	p2 := p1
	p2.Name = "Lydia"
	fmt.Printf("p1.Id=%d,p1.Name=%s,p1.Age=%d\n", p1.Id, p1.Name, p1.Age)
	fmt.Printf("p2.Id=%d,p2.Name=%s,p2.Age=%d\n", p2.Id, p2.Name, p2.Age)
	p3 := &p1
	p3.Name = "Tony"
	fmt.Printf("p1.Id=%d,p1.Name=%s,p1.Age=%d\n", p1.Id, p1.Name, p1.Age)
	fmt.Printf("p3.Id=%d,p3.Name=%s,p3.Age=%d\n", p3.Id, p3.Name, p3.Age)
}

结构体之间强转

package main

import "fmt"

type A struct {
	Num int
}

type B struct {
	Num int
}

//结构体进行type重新定义,相当于取别名
type AA A
type Integer int //基本数据类型也可以

func main() {
	//结构体之间的转换
	var a A
	var b B
	a = A(b) //两个结构体之间字段数量、字段类型、字段名称一致,可以强制转换
	fmt.Println(a, b)
	//结构体进行type重新定义,相当于取别名
	var integer Integer = 10
	var i int = 20
	i = int(integer) //并不能直接i = j,虽然本质上都是int,但是golang认为并不是同一种数据类型了,还是需要强转
	fmt.Println(integer, i)
}

结构体内存简单分析

package main

import "fmt"

//坐标点
type coordinates struct {
	x, y int
}

//线
type line struct {
	startPoint, endPoint coordinates
	array                *[2]int
}

func main() {
	//定义一条直线
	l1 := &line{startPoint: coordinates{x: 1, y: 1}, endPoint: coordinates{x: 3, y: 6}}
	fmt.Printf("l1 type=%T\n", l1)
	fmt.Printf("l1=%v\n", l1)
	//通过内存地址可以看出这四个值在内存里是连续的:0xc0000101a0,0xc0000101a8,0xc0000101b0,0xc0000101b8
	//每个字段地址之间相差8个字节,int类型在64位操作系统中占用8个字节
	fmt.Printf("l1.startPoint.x=%v, address=%p\n", l1.startPoint.x, &l1.startPoint.x)
	fmt.Printf("l1.startPoint.y=%v, address=%p\n", l1.startPoint.y, &l1.startPoint.y)
	fmt.Printf("l1.endPoint.x=%v, address=%p\n", l1.endPoint.x, &l1.endPoint.x)
	fmt.Printf("l1.endPoint.y=%v, address=%p\n", l1.endPoint.y, &l1.endPoint.y)
	//如果结构体中的某个字段是指针类型,那么该指针对应的值就不一定是连续的了,但是指针自己的地址在该结构体中仍然是连续的
	//可以看到l1.array[0]和l1.array[1]的地址与l1.endPoint.y并不连续,但是l1.array与l1.endPoint.y连续
	a1 := [...]int{8, 9}
	(*l1).array = &a1
	fmt.Printf("l1.array address=%p\n", &l1.array)
	fmt.Printf("l1.array[0]=%v, address=%p\n", l1.array[0], &l1.array[0])
	fmt.Printf("l1.array[1]=%v, address=%p\n", l1.array[1], &l1.array[1])
}

你可能感兴趣的:(#,Golang入门&语法,golang,struct,初始化,指针)