• go 基础 结构体


    结构体是类型中带有成员的复合类型。go语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性。

    go语言中的类型可以被实例化,使用new和&构造类型实例的类型是类型的指针。

    结构体成员是由一系列成员变量构成,成员(字段)有以下属性:

    • 字段名称唯一;
    • 拥有类型和值;
    • 成员的类型可以是结构体,甚至是字段所在结构体的类型。

    go不支持”类“的概念,也不支持"继承"面向对象的概念。

    go 语言不仅认为结构体能拥有方法,且每种自定义类型也可以有自己的方法。

    在函数外部定义结构体,作用域是全局的。

    结构体基础

    定义结构体

    type 结构体名称 struct {
    	字段名 字段类型
        ...
    }
    
    • 结构体类型名在包内不能重复

    示例,表示直角坐标系中的点的坐标

    type Point struct {
        X int
        Y int
    }
    

    实例化结构体--为结构体分配内存并初始化

    结构体定义只是一种内存布局的描述,只有结构化后才能真正分配内存。

    基本的实例化形式

    示例,表示直角坐标系中的点的坐标

    type Point struct {
        X int
        Y int
    }
    
    var p Point
    p.x = 10
    p.y = 20
    

    创建指针类型的结构体

    使用new关键字对类型进行实例化,会形成指针类型的结构体。

    type Player struct {
        Name string
        HealthPoint int
        MagicPoint int
    }
    
    tank := new(Player)
    tank.name = "Canon"
    tank.HealthPoint = 300
    

    go 语言中访问成员变量可以继续使用”.“,go增加了语法糖,将ins.Name转化为(*ins).Name

    取结构体地址实例化

    对结构体进行&取地址,视为对该类型进行一次new实例化操作。

    ins := &T{}
    
    • T表示结构体类型
    • Ins 为结构体实例,类型是*T

    示例,定义一个命令行指令,指令包含名臣,关联变量和注释

    type Command struct {
        Name string
        Var *int       // 此处使用指针,可以随时与绑定的值保持同步
        Comment string
    }
    
    var version int = 1
    cmd := &Command{}
    cmd.Name = "version"
    cmd.Var = &version
    cmd.Comment = "show version"
    

    初始化结构体成员变量

    使用基本形式初始化结构体

    示例,颜色的RGB值

    type Color struct {
        R, G, B byte
    }
    

    使用键值对初始化结构体

    示例,描述家庭任务关联

    type People struct {
    	name  string
    	child *People
    }
    
    relationship := &People{
    	name: "grand father",
    	child: &People{
    		name: "Dad",
    		child: &People{
    			name: "I",
    		},
    	},
    }
    fmt.Println(relationship.child.child.name)
    

    使用多个值列表初始化结构体

    注意

    • 必须初始化结构体的所有字段
    • 初始值与字段顺序保持一致
    • 键值对与值列表的形式不能混用

    示例,地址

    type Address struct {
        Privince string
        City string
        ZipCode int
        PhoneNumber string
    }
    
    addr := Address{
        "上海",
        "上海",
        "222300",
        "0"
    }
    

    构造函数--结构体初始化的函数封装

    go语言或者结构体没有构造函数的功能,结构体的初始化的过程可以用函数封装实现。

    模拟构造函数重载

    示例,根据颜色和名称可以构造不同猫的实例。

    type Cat struct {
        Name string
        COlor string
    }
    
    func NewCatByName(name string) *Cat {
        return &Cat{
            Name: name,
        }
    }
    
    func NewCatByColor(color string) *Cat {
        return &Cat{
            Color: color,
        }
    }
    

    模拟父级构造调用

    示例,黑猫是一种猫,猫是黑猫的泛称。

    package main
    
    import "fmt"
    
    type Cat struct {
    	Name  string
    	Color string
    }
    
    type BlackCat struct {
    	Cat // 嵌入Cat,类似于派生
    }
    
    func NewCat(name string) *Cat {
    	return &Cat{
    		Name: name,
    	}
    }
    
    func NewBlackCat(name string) *BlackCat {
    	cat := &BlackCat{}
    	cat.Color = "black"
    	cat.Name = name
    	return cat
    }
    
    func main() {
    	cat := NewCat("wow")
    	fmt.Println(cat)
    	blackcat := NewBlackCat("hello")
    	fmt.Println(blackcat)
    }
    

    方法

    使用背包作为"对象",将物品放入背包的过程称为”方法“。

    面向过程的实现方法

    面向过程中没有“方法”概念,只能通过结构体和函数,由使用者用函数参数和调用关系来形成接近”方法“的概念。

    package main
    
    import "fmt"
    
    type Bag struct {
    	items []int
    }
    
    func Insert(b *Bag, itemid int) {
    	b.items = append(b.items, itemid)
    }
    
    func main() {
    	bag := &Bag{}
    	Insert(bag, 100)
    	fmt.Println(bag.items)
    }
    

    Go 语言结构体方法

    将背包及放入背包物品中使用go语言的结构体和方法方式编写,为 *Bag创建一个方法。

    package main
    
    import "fmt"
    
    type Bag struct {
    	items []int
    }
    
    func (b *Bag) Insert(itemid int) {
    	b.items = append(b.items, itemid)
    }
    
    func main() {
    	bag := &Bag{}
    	bag.Insert(100)
    	fmt.Println(bag.items)
    }
    

    Insert(itemid int)的写法与函数一致,(b *Bag)表示接收器,即Insert作用的对象实例。每个方法只能有一个接收器。

    接收器--方法作用的目标

    image

    func (接收器变量 接收器类型) 方法名(参数列表) (返回参数) {}
    

    指针和非指针接收器的使用

    在计算机中,小对象由于值复制时的速度较快,适合使用非针接收器。大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递 不进行复制, 只是传指针。

    指针类型接收器

    指针类型接收器由一个结构体指针组成,更接近于面向对象中的thisself

    由于指针的特性,调用方法时,修改接收器成员变量,在方法结束后是有效的。

    package main
    
    import "fmt"
    
    type Property struct {
    	value int
    }
    
    func (p *Property) SetValue(value int) {
    	p.value = value
    }
    
    func (p *Property) Value() int {
    	return p.value
    }
    
    func main() {
    	p := &Property{}
    	p.SetValue(1)
    	fmt.Println(p.Value())
    }
    

    非指针类型接收器

    当方法作用于非指针接收器时,go语言会在代码运行时将接收器的值复制一份。在非指针接收器的方法中可以获取接收器的成员值,但修改后无效

    package main
    
    import "fmt"
    
    type Point struct {
    	X int
    	Y int
    }
    
    func (p Point) Add(other Point) Point {
    	return Point{p.X+other.X, p.Y+other.Y}
    }
    
    func main() {
    	p1 := Point{1, 1}
    	p2 := Point{3, 4}
    	fmt.Println(p1.Add(p2))
    }
    

    示例,time时间的中的Second属性是 Duration,Duration拥有String()方法。

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	fmt.Println(time.Second.String())
    }
    
    
    //const (
    //	Nanosecond  Duration = 1
    //	Microsecond          = 1000 * Nanosecond
    //	Millisecond          = 1000 * Microsecond
    //	Second               = 1000 * Millisecond
    //	Minute               = 60 * Second
    //	Hour                 = 60 * Minute
    //)
    //
    //func (d Duration) String() string {
    //	...
    //	return string(buf[w:])
    

    结构体内嵌

    结构体允许其成员字段在声明时没有宇段名而只有类型,这种形式的字段被称为类型内嵌。

    type Data struct {
    	int
    	float32
    	bool
    }
    
    ins : = &Data{
    	int: 1 0,
    	float32 : 3 .14,
    	bool: true
    }
    

    结构体类型内嵌比普通类型内嵌的概念复杂 ,下面通过一个实例来理解。

    package main
    
    import "fmt"
    
    type BasicColor struct {
    	R, G, B float32
    }
    
    type Color struct {
    	Basic BasicColor
    	Alpha float32
    }
    
    func main() {
    	var color Color
    	color.Basic.R = 1
    	color.Basic.G = 1
    	color.Basic.B = 0
    	color.Alpha = 1
    	fmt.Printf("%+v", color)
    }
    

    将 BasicColor 结构体嵌入Color 结构体中, BasicColor 没有宇段名而只有类型,这种写法就叫做结构体内嵌。

    package main
    
    import "fmt"
    
    type BasicColor struct {
    	R, G, B float32
    }
    
    type Color struct {
    	BasicColor
    	Alpha float32
    }
    
    func main() {
    	var color Color
    	color.R = 1
    	color.G = 1
    	color.B = 0
    	color.Alpha = 1
    	fmt.Printf("%+v", color)
    }
    

    初始化结构体内嵌

    package main
    
    import "fmt"
    
    type Wheel struct {
    	Size int
    }
    
    type Engine struct {
    	Power int
    	Type string
    }
    
    type Car struct {
    	Wheel
    	Engine
    }
    
    func main() {
    	car := Car{
    		Wheel: Wheel{
    			Size: 10,
    		},
    		Engine: Engine{
    			Power: 10,
    			Type: "Dz",
    		},
    	}
    
    	fmt.Printf("%+v", car)
    }
    

    使用匿名结构体分离json数据

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    // 定义屏幕
    type Screen struct {
    	Size float32 // 屏幕尺寸
    	ResX, ResY int //屏幕水平和垂直分辨率
    }
    
    // 定义电池
    type Battery struct {
    	Capacity int // 容量
    }
    
    func genJsonData () []byte {
    	raw := &struct {
    		Screen
    		Battery
    		HasTouchID bool
    	}{
    		Screen: Screen{
    			Size: 5.5,
    			ResX: 1920,
    			ResY: 1080,
    		},
    		Battery: Battery{
    			Capacity: 100,
    		},
    		HasTouchID: true,
    	}
    	jsonData, err := json.Marshal(raw)
    	if err != nil {
    		return make([]byte, 0)
    	} else {
    		return jsonData
    	}
    }
    
    func main() {
    	// 生成一段 JSON 数据
    	jsonData := genJsonData()
    	fmt.Println(string(jsonData))
    	// 只需要屏幕和指纹识别信息的结构和实例
    	screenAndTouch := struct {
    		Screen
    		HasTouchID bool
    	}{}
    
    	// 反序列化到 screenAndTouch
    	err := json.Unmarshal(jsonData, &screenAndTouch)
    	if err == nil {
    		fmt.Printf("%+v
    ", screenAndTouch)
    	}
    
    	// 只需要电池和指纹识别信息的结构和实例
    	batteryAndTouch := struct {
    		Battery
    		HasTouchID bool
    	}{}
    
    	err = json.Unmarshal(jsonData, &batteryAndTouch)
    	if err == nil {
    		fmt.Printf("%+v
    ", &batteryAndTouch)
    	}
    }
    
  • 相关阅读:
    美国队长
    weka数据预处理
    weka特征选择(IG、chi-square)
    生成arff文件,csv转为arff
    logistic regression的一些问题,不平衡数据,时间序列,求解惑
    Feature Scaling
    【转】机器学习问题方法总结
    Canopy算法聚类
    ROC曲线及AUC评价指标
    评估指标:准确率(Precision)、召回率(Recall)以及F值(F-Measure)
  • 原文地址:https://www.cnblogs.com/hiyang/p/12616500.html
Copyright © 2020-2023  润新知