compose_test
package main
import "fmt"
type Teacher struct {
Name string
Age int
Title string
}
func (t Teacher) teacherInfo() {
fmt.Printf("姓名:%s, 年龄:%d, 职称:%s", t.Name, t.Age, t.Title)
}
type Course struct {
Teacher //如果讲师的信息比较多怎么办?将另一个结构体的变量放进来
Name string
Price int
Url string
}
//匿名嵌套 这种做法其实就是我们的语法糖
func (c Course) courseInfo() {
fmt.Printf("课程名:%s, 价格:%d, 讲师信息:%s %d %s", c.Name, c.Price,
c.Teacher.Name, c.Age, c.Title)
}
//这种继承的效果有点说服不了人
func main() {
//go语言的继承 组合
t := Teacher{
Name: "anwma",
Age: 18,
Title: "开发",
}
c := Course{
Teacher: t,
Price: 100,
Url: "",
Name: "django",
}
c.courseInfo()
//c := Course{
// Teacher: Teacher{
// Name: "anwma",
// Age: 18,
// Title: "rd",
// },
//}
}
new_pkg
package new_pkg
type Course struct {
Name string
Price int
Url string
}
struct_tag
package main
import (
"encoding/json"
"fmt"
"reflect"
)
//type Info struct { //能表述的信息是有限的
// // python中使用元类编程
// Name string //name是映射成mysql中的char类型还是varchar类型还是text类型, 即使能够说明 但是额外的信息max_length
// //Age int
// //Age int `json:"age,omitempty"`
// Age int //不加 默认值为0
// Gender string
//}
// Info 结构体能基本上达到类的一个效果 多态
type Info struct {
Name string `orm:"name,max_length = 17,min_length = 5"`
Age int `orm:"age,min = 18,max = 70"`
Gender string `orm:"gender,required"`
}
//反射包
func main() {
//结构体标签
/*
结构体的字段除了名字和类型外,还可以有一个可选的标签(tag):
它是一个附属于字段的字符串,可以是文档或其他的重要标记。
比如在我们解析json或生成json文件时,常用到encoding/json包,
它提供一些默认标签,例如:omitempty标签可以在序列化的时候忽略0值或者空值。
而-标签的作用是不进行序列化,其效果和和直接将结构体中的字段写成小写的效果一样。
*/
info := Info{
Name: "Wozen",
//Age: 0,
Gender: "男",
}
re, _ := json.Marshal(info)
fmt.Println(string(re))
//通过反射包去识别这些tag 简答的体验了一下反射的威力 spring 底层都是反射
t := reflect.TypeOf(info)
fmt.Println("Type:", t.Name())
fmt.Println("Kind:", t.Kind())
//Output:
//Type: Info
//Kind: struct
for i := 0; i < t.NumField(); i++ {
field := t.Field(i) //获取结构体的每一个字段
tag := field.Tag.Get("orm")
fmt.Printf("%d. %v (%v),tag: '%v'\n", i+1, field.Name, field.Type.Name(), tag)
}
//具体的应用绝大部分情况之下我们是不需要使用到反射的 实际开发的项目中会用到的
}
struct_test
package main
import (
"fmt"
"unsafe"
)
type Course struct {
Name string
Price int
Url string
}
// 结构体绑定方法 函数的接收者
func (c Course) printCourseInfo() {
fmt.Printf("课程名: %s, 课程价格: %d, 课程的地址: %s", c.Name, c.Price, c.Url)
}
func (c *Course) setPrice(price int) {
c.Price = price
}
//结构体的方法只能和结构体在同一个包中
//2.内置的int类型不能加方法
func main() {
//go语言不支持面向对象
//面向对象的三个基本特征:封装 继承 多态 方法重载 抽象基类(不支持)
//定义struct go语言没有class这个概念 所以说对于很多人来说会少理解很多面向对象抽象的概念
//1.实例化 k-v方式
//var c new_pkg.Course = new_pkg.Course{
// Name: "django",
// Price: 100,
// Url: "https://www.imooc.com",
//}
//访问
//fmt.Println(c.Name, c.Price, c.Url)
//大小写在go语言中的重要性 可见性
//一个包中的变量或者结构体如果首字母是小写,那么对于另一个包不可见
//机构体定义的 名称 以及属性首字母大写很重要
//2.第二种实例化方式 - 顺序形式
//c2 := Course{"scrapy", 110, "https://www.imooc.com"}
//fmt.Println(c2.Name, c2.Price, c2.Url)
//3.如果一个指向结构体的指针 通过结构体指针获取对象的值
//c3 := &Course{"tornado", 100, "https://www.imooc.com"}
//fmt.Printf("%T\n", c3)
//fmt.Println((*c3).Name, (*c3).Price, (*c3).Url)
//fmt.Println("--------------")
//应该能看出来 go语言实际上在借鉴很多动态语言的特性 -很多地方不管如何写都是正确的
//另一个根本原因 go语言的指针是受限的
//fmt.Println(c3.Name, c3.Price, c3.Url) //这里其实是go语言的一个语法糖 go语言内部会将c3转换为(*c3)
//4.零值 如果不给结构体赋值 go语言会默认给每个字段采用默认值
//c4 := Course{}
//fmt.Println(c4.Name)
//5.多种方式零值初始结构体
//var c5 Course = Course{}
//var c6 Course
//var c7 *Course = new(Course)
//var c8 *Course
//var c9 *Course = &Course{}
//为什么c6和c8表现出来的结果不一样 指针如果只声明不赋值 默认值是nil c6不是指针 是结构体的类型
//fmt.Println("零值初始化")
//fmt.Println(c5.Price)
//fmt.Println(c6.Price)
//fmt.Println(c7.Price)
//fmt.Println(c8.Price)
//fmt.Println(c9.Price)
//6.结构体是值类型
c10 := Course{"scrapy", 110, "https://www.imooc.com"}
c11 := c10
fmt.Println(c10)
fmt.Println(c11)
c10.Price = 200
fmt.Println(c10)
fmt.Println(c11)
//go语言中struct无处不在
//7.结构体的大小 占用内存的大小 可以使用sizeof来查看对象占用的类型
fmt.Println(unsafe.Sizeof(1)) //8
//go语言string的本质 其实string是一个结构体 16个字节
//type string struct {
// Data uintptr //指针占8个长度
// Len int //长度64位系统占8个长度
//}
fmt.Println(unsafe.Sizeof("scrapy")) //16
fmt.Println(unsafe.Sizeof(c10)) //16
//8.slice的大小 24个字节
type slice struct {
array unsafe.Pointer //底层数组地址
len int //长度
cap int //容量
}
s1 := []int{1, 2, 4, 5}
s2 := []string{"hello"}
fmt.Println("切片的大小:")
fmt.Println(unsafe.Sizeof(s1))
fmt.Println(unsafe.Sizeof(s2))
m1 := map[string]string{
"hello1": "world1",
"hello2": "world2",
"hello3": "world3",
}
fmt.Println(unsafe.Sizeof(m1)) //8
//结构体方法 达到了封装数据和封装方法的效果
c10 = Course{"scrapy", 100, "https://www.imooc.com"}
//Course.printCourseInfo(c10)
//Course.setPrice(c10, 200)
(&c10).setPrice(200) //修改c10的price?为什么呢? 内部转换 语法糖 函数参数的传递是怎么传递的 结构体是值传递
fmt.Println(c10.Price)
//c10.printCourseInfo()
//结构体的接收者有两种形式 1.值传递2.指针传递 如果你想改结构体的值 如果结构体的数据很大
//go语言不支持继承 但是有办法能达到同样的效果 组合
}
type_test
package main
import "fmt"
func main() {
//go语言中的关键词 type
//1.给一个类型定义别名,实际上为什么会有byte 就是我为了强调我们现在处理的对象是字节类型
//2.这种别名实际上还是为了代码的可读性,这个实质上本质仍然是uint8 无非就是在代码编码阶段可读性强而已
//rune byte
type myByte = byte
var b myByte
fmt.Printf("%T\n", b)
//3.第二种就是基于一个已有的类型定义一个新的类型
type myInt int
var i myInt
fmt.Printf("%T\n", i)
//4.定义结构体
type Course struct {
name string
price int
}
//5.定义接口、
type Callable interface {
}
//6.定义函数别名
type handle func(str string)
}