You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
5.3 KiB

  1. # 结构体
  2. 结构体是一个复合类型,用于表示一组数据。
  3. 结构体由一系列属性组成,每个属性都有自己的类型和值。
  4. ## 初始化
  5. ```go
  6. // 定义一个结构体(类型),每个结构体包含 name、age、hobby 三个元素
  7. type Person struct {
  8. name string
  9. age int
  10. hobby []string
  11. }
  12. //方式1:先后顺序
  13. var p1 = Person{"lihui", 22, []string{"唱跳", "rap"}}
  14. fmt.Println(p1.name, p1.age, p1.hobby)
  15. //方式2:关键字
  16. var p2 = Person{name: "lihui", age: 22, hobby: []string{"饺子", "馒头"}}
  17. fmt.Println(p2.name, p2.age, p2.hobby)
  18. //方式3:先声明再赋值
  19. var p3 Person
  20. p3.name = "lihui"
  21. p3.age = 18
  22. p3.hobby = []string{"唱跳", "篮球"}
  23. fmt.Println(p3.name, p3.age, p3.hobby)
  24. ```
  25. ## 结构体指针
  26. ```go
  27. type Person struct {
  28. name string
  29. age int
  30. }
  31. // 初始化结构体(创建一个结构体对象)
  32. p1 := Person{"lihui", 18}
  33. fmt.Println(p1.name, p1.age)
  34. // 初始化结构体指针
  35. // var p2 *Person = &Person{"lihui", 18}
  36. p2 := &Person{"lihui", 18}
  37. fmt.Println(p2.name, p2.age)
  38. var p3 *Person = new(Person)
  39. p3.name = "lihui"
  40. p3.age = 18
  41. fmt.Println(p3.name, p3.age)
  42. ```
  43. ## 赋值拷贝
  44. 其实本质上都拷贝了,只不过由于数据存储方式的不同,导致拷贝的有些是数据,有些是内存地址(指针)。
  45. 但是:
  46. - 感觉拷贝:字符串、数组、整型等。
  47. - 感觉不拷贝:map、切片。
  48. ## 标签
  49. 没啥用,给结构体的元素一个注释
  50. ## 补充
  51. 结构体做参数和返回值时,在执行时候都会被重新拷贝一份,如果不想被拷贝,则可以通过指针的形式进行处理。
  52. ## 类型方法
  53. ```go
  54. package main
  55. import "fmt"
  56. // 声明类型
  57. type MyInt int
  58. // 为MyInt类型自定义一个指针方法
  59. // 可以是指针/可以是类型:*MyInt MyInt
  60. // 不使用对象,可以用 _ 代替
  61. func (_ *MyInt) DoSomething(a1 int, a2 int) int {
  62. return a1 + a2
  63. }
  64. func do(a1 int,a2 int) int{
  65. return a1 + a2
  66. }
  67. func main() {
  68. var v1 MyInt = 1
  69. result := v1.DoSomething(1, 2)
  70. fmt.Println(result)
  71. }
  72. ```
  73. ## 方法继承
  74. ```go
  75. package main
  76. import "fmt"
  77. type Base struct {
  78. name string
  79. }
  80. type Son struct {
  81. Base // 匿名的方式,如果改成 base Base 则无法继承Base的方法。
  82. age int
  83. }
  84. // Base结构体的方法
  85. func (b *Base) m1() int {
  86. return 666
  87. }
  88. // Son结构体的方法
  89. func (s *Son) m2() int {
  90. return 999
  91. }
  92. func main() {
  93. son := Son{age: 18, Base: Base{name: "lihui"}}
  94. result1 := son.m1()
  95. result2 := son.m2()
  96. fmt.Println(result1, result2)
  97. }
  98. ```
  99. ## 结构体工厂
  100. Go 语言不支持面向对象编程语言中那样的构造方法,但是可以很容易的在 Go 中实现 “构造工厂”方法。为了方便通常会为类型定义一个工厂,按惯例,工厂的名字以 new 或 New 开头。假设定义了如下的 File 结构体类型:
  101. ```go
  102. type File struct {
  103. fd int
  104. name string
  105. }
  106. // 20...
  107. f := File{10, "xxxxxx"}
  108. ```
  109. ```go
  110. type File struct {
  111. fd int
  112. name string
  113. }
  114. func NewFile(fd int, name string) *File {
  115. // 20...
  116. return &File{fd, name}
  117. }
  118. func main() {
  119. f1 := NewFile(10, "./test.txt")
  120. f2 := File{10, "xxxxxx"}
  121. }
  122. ```
  123. 在 Go 语言中常常像上面这样在工厂方法里使用初始化来简便的实现构造函数。
  124. **强制使用工厂方法**,让结构体变为私有,工厂方法变为共有,这样强制所有代码在实例化结构体是都是用工厂方法。
  125. 可以用包导入时首字母大写共有的方式来实现。
  126. # 函数
  127. 可以把函数当做一个代码块,用于实现某个功能。并且提高代码的重用性和可读性。
  128. ```go
  129. func 函数名(参数) 返回值 {
  130. 函数体
  131. }
  132. ```
  133. 关于函数名需要注意:函数名只能是字母数字下划线组合且数字不能开头,即驼峰式命名
  134. ## 闭包
  135. ```go
  136. package main
  137. import "fmt"
  138. func main() {
  139. var functionList []func()
  140. for i := 0; i < 5; i++ {
  141. function := func() {
  142. fmt.Println(i)
  143. }
  144. functionList = append(functionList, function)
  145. }
  146. functionList[0]()
  147. functionList[1]()
  148. functionList[2]()
  149. }
  150. ```
  151. ## defer延长执行
  152. ```go
  153. package main
  154. import "fmt"
  155. func do() int {
  156. fmt.Println("风吹")
  157. defer fmt.Println("函数执行完毕了") // 如果在这行之前执行return,那么defer就不再执行
  158. fmt.Println("屁屁凉")
  159. return 666
  160. }
  161. func main() {
  162. ret := do()
  163. fmt.Println(ret)
  164. }
  165. ```
  166. 多个defer 按照写的先后顺序,以倒序执行
  167. ```go
  168. package main
  169. import "fmt"
  170. func other(a1 int, a2 int) {
  171. fmt.Println("defer函数被执行了")
  172. }
  173. func do() int {
  174. fmt.Println("风吹")
  175. defer fmt.Println("函数执行完毕了")
  176. defer other(1, 22)
  177. fmt.Println("屁屁凉")
  178. return 666
  179. }
  180. func main() {
  181. ret := do()
  182. fmt.Println(ret)
  183. }
  184. ```
  185. ## 自执行函数
  186. ```go
  187. result := func(arg int) int {
  188. return arg + 100
  189. }(123)
  190. fmt.Println(result) // 223
  191. ```
  192. # 接口
  193. 接口,用于约束和泛指数据类型
  194. ```go
  195. type 接口名称 interface{
  196. 方法名称() 返回值
  197. }
  198. ```
  199. ```go
  200. type Base interface {
  201. f1() // 定义方法,无返回值
  202. f2() int // 定义方法,返回值int类型
  203. f3() (int, bool) // 定义方法,2个返回值分别是 int、bool类型
  204. f4(n1 int, n2 int) int // 定义方法,需要两个参数,1个返回值
  205. }
  206. type empty interface {} // interface{}
  207. ```
  208. 接口中的方法只定义,不能编写具体的实现逻辑。