基础语法·中(golang笔记第二期)

p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解

目录

结构体

go 复制代码
package main

import "fmt"

//声明一种行数据类型 myint, 是int的一个别名
type myint int

//定义一个结构体
type Book struct {
	title string
	auth  string
}

func changeBook(book Book) {
	//传递一个book的副本
	book.auth = "lisi"
}

func changeBook2(book *Book) {
	//指针传递才能修改原始数据
	book.auth = "wangwu"
}

func main() {

	var book1 Book
	book1.title = "Golang"
	book1.auth = "zhangsan"

	fmt.Printf("%v\n", book1)

	changeBook(book1)

	fmt.Printf("%v\n", book1)

	changeBook2(&book1)

	fmt.Printf("%v\n", book1)
}

封装

go 复制代码
package main

import "fmt"

//如果类名首字母大写,表示其他包也能够访问
type Hero struct {
    //如果说类的属性首字母大写,表示该属性是对外能够访问的,否则的话只能够类的内部访问
    Name  string
    Age    int
    Level int
}

func (this Hero) Show() {
    fmt.Println("Name = ", this.Name)
    fmt.Println("Age = ", this.Age)
    fmt.Println("Level = ", this.Level)
}

func (this *Hero) GetName() string {
    return this.Name
}

// func (this Hero) SetName(newName string) {
// 	//值拷贝,修改的是副本
//     this.Name = newName
// }

func (this *Hero) SetName(newName string) {
    this.Name = newName
}

func main() {
    //创建一个对象
    hero := Hero{Name: "zhangsan", Age: 100, Level: 1}

    hero.Show()

    hero.SetName("lisi")

    hero.Show()
}

继承

go 复制代码
package parent
import "fmt"

type Parent struct {
	Name string
	Age  int
}

func (this Parent) Show() {
	println("Name = ", this.Name)
	println("Age = ", this.Age)
}

func (this Parent) Eat() {
	fmt.Println("Parent is eating.")
}
go 复制代码
package main

import "fmt"
import "src/parent"
type Child struct {
    parent.Parent //继承了Parent类
    Grade int
}

//重写父类方法
func (this Child) Eat() {
    fmt.Println("Child is eating.")
}

//子类的新方法
func (this Child) Study() {
    fmt.Println("Child is studying.")
}
func main() {
    p:= parent.Parent{"Tom", 40}
    p.Show()
    p.Eat()
    c := Child{parent.Parent{"Tom", 40}, 5}
    c.Show() //调用父类方法
    c.Eat()
    c.Study()

    // var c2 Child
    // c2.Name = "Jerry"
    // c2.Age = 10
    // c2.Grade = 3
    // c2.Show()
}

多态

go 复制代码
package main

import "fmt"

//本质是指针
type Animal interface {
    Sleep()
    GetClolor() string
    GetType() string
}

type Cat struct {
    Color string
}

type Dog struct {
    Color string
}

func (this Cat) Sleep() {
    fmt.Println("Cat is sleeping.")
}

func (this Cat) GetClolor() string {
    return this.Color
}

func (this Cat) GetType() string {
    return "Cat"
}

func (this Dog) Sleep() {
    fmt.Println("Dog is sleeping.")
}

func (this Dog) GetClolor() string {
    return this.Color
}

func (this Dog) GetType() string {
    return "Dog"
}

func main() {
    var animal1 Animal
    animal1 = Cat{"Yellow"}
    fmt.Printf("Animal type: %s, color: %s\n", animal1.GetType(), animal1.GetClolor())
    animal1.Sleep()

    var animal2 Animal
    animal2 = Dog{"Black"}
    fmt.Printf("Animal type: %s, color: %s\n", animal2.GetType(), animal2.GetClolor())
    animal2.Sleep()

}

多态三要素:

有一个父类(有接口)

有子类(实现了父类的全部接口方法)

父类类型的变量(指针)指向(引用)子类的具体数据变量

万能数据类型

go 复制代码
package main

import "fmt"

//interface{}是Go语言中的空接口类型,可以接受任何类型的值。它是所有类型的父类型,因此可以用来存储任何类型的数据,即万能数据类型
func myFunc(arg interface{}){
    fmt.Println(arg)

    //给interface{}类型的参数进行类型断言,判断它是否是某个具体的类型
    if str, ok := arg.(string); ok {
        fmt.Println("这是一个字符串:", str)
    } else if num, ok := arg.(int); ok {
        fmt.Println("这是一个整数:", num)
    } else if book, ok := arg.(Book); ok {
        fmt.Println("这是一本书,作者是:", book.Author)
    } else {
        fmt.Println("未知类型")
    }
}


type Book struct {
    Author string
}
func main() {
book :=Book{"zhangsan"}

myFunc(book)
myFunc(123)
myFunc("Hello, World!")
}

反射

静态类型、具体类型


在 Go 语言中,理解"静态类型"与"接口的动态类型"是掌握其类型系统、多态性和反射机制的关键。这两者代表了类型在不同生命周期(编译时与运行时)的不同表现形式。

  1. 静态类型
    静态类型,也称为编译时类型,是 Go 语言作为静态类型语言的根本体现。
    定义:静态类型指的是变量、常量、函数参数和返回值在代码声明阶段就已被明确指定的类型。这个类型信息是固定写在源代码中的。
    核心特征:
    编译时确定与检查:编译器在将源代码转换为可执行程序的过程中,会完全知晓并验证所有实体的静态类型。任何不符合类型规则的赋值、传参或运算都会导致编译错误,程序无法生成。这为程序提供了强大的、早期(运行前)的类型安全保障。
    不可变性:一个变量一旦被声明为某种静态类型(如 int, string, 或自定义的 struct),在它的整个生命周期内,其静态类型不会改变。你可以改变变量的值,但不能改变它"是什么类型"的这一事实。
    性能优化基础:由于编译器确切知道每个数据的类型,它可以进行深度的优化,例如生成更高效的机器指令、进行内联优化等,从而提升程序运行性能。
    代码清晰性:明确的静态类型声明本身就是一种文档,它清晰地表明了数据的用途和预期的操作,提高了代码的可读性和可维护性。
    举例说明:当你写下 var count int时,count的静态类型就是 int。编译器会确保你只能给 count赋值整数,也只能对它进行整数所允许的操作。如果你尝试写入一个字符串,编译器会立即报错。
  2. 接口的动态类型
    动态类型的概念与 Go 的接口机制紧密相关,它体现了 Go 实现多态(一个接口,多种实现)的方式。
    定义:当一个变量被声明为某个接口类型时,该变量的"动态类型"指的是在程序实际运行时刻,存储在该接口变量中的那个具体值的实际类型。
    核心特征:
    运行时确定:与静态类型在编译时确定不同,动态类型要到程序执行时才能知晓。同一个接口类型的变量,在不同的执行时刻,其内部可能包裹着完全不同具体类型的值。
    实现多态的基础:这是 Go 语言实现"面向接口编程"和"多态"的核心。你可以定义一个 io.Writer接口类型的变量,在运行时,它可以指向一个向文件写入的 *os.File对象,也可以指向一个在内存中缓冲数据的 *bytes.Buffer对象。调用其 Write方法时,实际执行的是当时所持有的具体类型的方法。
    需要类型断言或反射探查 :由于编译器在编译时只知道变量是某个接口类型,而不知道其动态的具体类型,因此当你需要访问具体类型独有的字段或方法时,必须使用类型断言(如 value, ok := var.(ConcreteType))或反射(reflect包)来"探查"和获取其动态类型信息。这个过程如果失败,可能会导致运行时恐慌。
    灵活性带来的代价:接口提供的动态类型能力增加了程序的灵活性,但类型断言和反射操作会带来微小的运行时开销,并且不当的使用会引入运行时错误的风险。
    举例说明:声明 var writer io.Writer。此时,writer的静态类型是 io.Writer(接口)。在运行时,你执行 writer = os.Stdout,那么此刻 writer的动态类型就是 *os.File。之后你又执行 writer = new(bytes.Buffer),此时 writer的动态类型就变成了 *bytes.Buffer。它的静态类型始终是 io.Writer,但动态类型随着赋值而改变。
go 复制代码
package main

import (
	"fmt"
	"reflect"
)

func reflectNum(arg interface{}) {
	fmt.Println("type : ", reflect.TypeOf(arg))
	fmt.Println("value : ", reflect.ValueOf(arg))
	fmt.Println("-----------------------------")
}

type Student struct {
	Name string
	Age  int
}

func reflectStruct(arg interface{}) {
	val := reflect.ValueOf(arg)
	typ := reflect.TypeOf(arg)
	fmt.Println("name : ", typ.Name())
	fmt.Println("kind : ", typ.Kind())
	fmt.Println(val)
	fmt.Println("-----------------------------")
	for i := 0; i < val.NumField(); i++ {
		fieldType := typ.Field(i)   // 获取字段类型信息
		fieldValue := val.Field(i)  // 获取字段值
		value := fieldValue.Interface()
		fmt.Printf("%s: %v = %v\n", fieldType.Name, fieldType.Type, value)
	}
}

func main() {
	var num float64 = 1.2345
	reflectNum(num)

	student := Student{Name: "Alice", Age: 20}
	reflectStruct(student)
}

解析tag

go 复制代码
package main

import (
    "fmt"
    "reflect"
)

type resume struct {
    Name string `info:"name" doc:"我的名字"`
    Sex  string `info:"sex"`
}

func findTag(str interface{}) {
    t := reflect.TypeOf(str).Elem()

    for i := 0; i < t.NumField(); i++ {
        taginfo := t.Field(i).Tag.Get("info")
        tagdoc := t.Field(i).Tag.Get("doc")
        fmt.Println("info: ", taginfo, " doc: ", tagdoc)
    }
}

func main() {
    var re resume

    findTag(&re)
}

解析json

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
)

type Movie struct {
	Title  string   `json:"title"`
	Year   int      `json:"year"`
	Price  int      `json:"rmb"`
	Actors []string `json:"actors"`
}

func main() {
	movie := Movie{"red alert 2", 2012, 17, []string{"zhangsan", "lisi"}}

	//编码的过程 结构体---> json
	jsonStr, err := json.Marshal(movie)
	if err != nil {
		fmt.Println("json marshal error", err)
		return
	}

	fmt.Printf("jsonStr = %s\n", jsonStr)

	//解码的过程 jsonstr ---> 结构体
	//jsonStr = {"title":"喜剧之王","year":2000,"rmb":10,"actors":["xingye","zhangbozhi"]}
	myMovie := Movie{}
	err = json.Unmarshal(jsonStr, &myMovie)
	if err != nil {
		fmt.Println("json unmarshal error", err)
		return
	}
    fmt.Println("myMovie = ", myMovie)
}
相关推荐
m0_569881472 小时前
C++中的适配器模式变体
开发语言·c++·算法
态态态2 小时前
平板PDF充足笔记空间的最优解
笔记·pdf
第二层皮-合肥2 小时前
基于C#的工业测试控制软件-总体框架
开发语言·c#
lsx2024062 小时前
ionic 单选框操作详解
开发语言
飞Link2 小时前
Python Pydantic V2 核心原理解析与企业级实战指南
开发语言·python
比昨天多敲两行2 小时前
C++ 多态
开发语言·c++
、BeYourself2 小时前
Scala 字面量
开发语言·后端·scala
Amumu121382 小时前
JS:ES6~ES11基础语法(二)
开发语言·前端·javascript