compose_test
package mainimport "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_pkgtype Course struct { Name string Price int Url string}
struct_tag
package mainimport ( "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 mainimport ( "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 mainimport "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)}