go结构体详解
go 是面向对象语言
封装
-
状态 (属性)
-
行为 (方法)
可见性/不可见性 (大写/小写)
可重用性
- 继承 (组合)
方法的重载
- 多态
接口
-
传统没,面向对象编程语言
-
数据结构构成一个类
-
你可以创建一个对象通过类的模板
-
类中封装了属性和方法
go中的类型
Go 类型:基本类型、引用类型、结构类型、自定义类型
Go 语言中,引用类型有 切片、字典(map)、接口、函数类型 以及 通道(chan) 。
结构类型是用来描述一组值的,比如一个人有身高、体重、名字和年龄等,本质上是一种聚合型的数据类型
类型别名 Go 的编译器不会像 Java 的那样,帮我们做隐式的类型转换。
package main
import "fmt"
type foo int
func main() {
var myAge foo
myAge = 44
fmt.Printf("%T %v \n", myAge, myAge)
}
结构体的初始化
type person struct {
first string
last string
age int
}
func main() {
p1 := person{"James", "Bond", 20}
p2 := person{"Miss", "Moneypenny", 18}
fmt.Println(p1.first, p1.last, p1.age)
fmt.Println(p2.first, p2.last, p2.age)
}
struct method 结构体的方法
type person struct {
first string
last string
age int
}
func (p person) fullName() string {
return p.first + p.last
}
func main() {
p1 := person{"James", "Bond", 20}
p2 := person{"Miss", "Moneypenny", 18}
fmt.Println(p1.fullName())
fmt.Println(p2.fullName())
}
组合类型 嵌入式类型
type person struct {
First string
Last string
Age int
}
type doubleZero struct {
person
LicenseToKill bool
}
func main() {
p1 := doubleZero{
person: person{
First: "James",
Last: "Bond",
Age: 20,
},
LicenseToKill: true,
}
p2 := doubleZero{
person: person{
First: "Miss",
Last: "MoneyPenny",
Age: 19,
},
LicenseToKill: false,
}
fmt.Println(p1.First, p1.Last, p1.Age, p1.LicenseToKill)
fmt.Println(p2.person.First, p2.Last, p2.Age, p2.LicenseToKill)
属性方法的覆盖
声明一个结构体类型的类型,若发生类型嵌套,如果外层没有内层的属性和方法则可以直接拿到内层的属性和方法
如果外层也声明了一样的熟悉和方法,则会发生覆盖,这跟面向对象的重写类似,在go中嵌套就是传统面向对象的继承
结构体的指针
结构体的指针可以改变该结构体的属性和方法
```go
type person struct {
name string
age int
}
func main() {
p1 := &person{"James", 20}
fmt.Println(p1)
fmt.Printf("%T\n", p1)
fmt.Println(p1.name)
fmt.Println(p1.age)
}
#### 结构体序列化
>结构体的属性要大写,不然不能够序列化
```go
type person struct {
First string
Last string
Age int
notExported int
}
func main() {
p1 := person{"James", "Bond", 20, 007}
bs, _ := json.Marshal(p1)
fmt.Println(bs)
fmt.Printf("%T \n", bs)
fmt.Println(string(bs))
}
变量作用域
包的变量
var x = 42
func main() {
fmt.Println(x)
foo()
}
func foo() {
fmt.Println(x)
}
包变量的作用域及可导出
在go中 变量或方法名为大写则意味着可导出,在同一个包中可以任意使用
// MyName is exported because it starts with a capital letter var MyName = "Todd" var yourName = "Future Rock Star Programmer"
变量在方法的作用域
func main() {
x := 42
fmt.Println(x)
foo()
}
func foo() {
// no access to x
// this does not compile
fmt.Println(x)
}
go的变量作用域
go的变量作用域是花括号确定的,任一变量的作用域只在自身所处的花括号范围内
if, for等可以有初始化表达式的,其作用域还要高于其后的花括号一层
闭包
if-else
普通if-else
if a==1{
fmt.Println("a=1")
}
if else 局部变量
if food := "Chocolate"; b {
a := true
if a {
food := "banana"
fmt.Println(food)
} else {
food := "apple"
fmt.Println(food)
}
fmt.Println(food)
}
if else else if else
if false {
fmt.Println("first print statement")
} else if true {
fmt.Println("second print statement")
} else {
fmt.Println("third print statement")
}
循环
for 循环
for i := 0; i <= 100; i++ {
fmt.Println(i)
}
for range
当用于遍历数组和切片的时候,range函数返回索引和元素;
当用于遍历字典的时候,range函数返回字典的键和值。
数组
普通数组
var a [23]int
fmt.Println(x)
fmt.Println(len(x))
fmt.Println(x[42])
x[42] = 777
fmt.Println(x[42])
字面量数组
[3]int [4]int是两种完全不同的类型
var q [3]int = [3]int{1, 2, 3} var r [3]int = [...]int{1, 2, 4}
切片
mySlice := []int{1, 3, 5, 7, 9, 11}
字典
make与 new的区别
接口
没有接口的解构体方法
type square struct {
side float64
}
func (z square) area() float64 {
return z.side * z.side
}
func main() {
s := square{10}
fmt.Println("Area: ", s.area())
}
有接口的结构体方法
type square struct {
side float64
}
func (z square) area() float64 {
return z.side * z.side
}
type shape interface {
area() float64
}
func info(z shape) {
fmt.Println(z)
fmt.Println(z.area())
}
func main() {
s := square{10}
fmt.Printf("%T\n",s)
info(s)
}
错误处理
发生错误没有进行异常处理
程序发生异常错误 fmt打印
```go
_, err := os.Open("no-file.txt")
if err != nil {
fmt.Println("err happened", err)
}
#### 发生错误没有进行异常处理
>程序发生异常错误 log打印
```go
_, err := os.Open("no-file.txt")
if err != nil {
// fmt.Println("err happened", err)
log.Println("err happened", err)
// log.Fatalln(err)
// panic(err)
}
发生错误没有进行异常处理
程序发生异常错误 log打印到文本里面
func init() {
nf, err := os.Create("log.txt")
if err != nil {
fmt.Println(err)
}
log.SetOutput(nf)
}
func main() {
_, err := os.Open("no-file.txt")
if err != nil {
// fmt.Println("err happened", err)
log.Println("err happened", err)
// log.Fatalln(err)
// panic(err)
}
}
异常处理函数
defer 表示永远在执行完成去执行defer后面的函数
func clean(){
fmt.Println(" do something in clean ")
}
func main(){
defer clean()
fmt.Println("end main")
}
defer
(基本功能)简单来讲,在defer所在函数执行完所有的代码之后,会自动执行defer的这个函数。
```go
func main() {
defer second()
first()
}
func first() {
fmt.Println("first")
}
func second() {
fmt.Println("second")
}
first
second
>局部函数
```go
func main() {
defer second()
defer third()
first()
}
func first() {
fmt.Println("first")
}
func second() {
fmt.Println("second")
}
func third() {
fmt.Println("third")
}
栈特性
```go
func main() {
defer second()
defer third()
first()
}
func first() {
fmt.Println("first")
}
func second() {
fmt.Println("second")
}
func third() {
fmt.Println("third")
}
>
### panic
>panic相当于一个运行时异常
>遇到panic的时候,会停止当前函数剩下来的语句,但在退出该函数之前,会执行defer的语句
>依据函数调用层次,panic依次终止每个函数,直至main()。
### recover
>recover相当于try-catch的catch部分,使得panic不再传递。而defer相当于try-catch-final的final部分。
```go
func main() {
f()
}
func final_print(msg string) {
fmt.Println(msg)
}
func f() {
fmt.Println("f.1")
g()
fmt.Println("f.2")
}
func g() {
defer func() {
str := recover()
fmt.Println(str)
}()
defer final_print("g.defer()")
fmt.Println("g.1")
h()
fmt.Println("g.2")
}
func h() {
defer final_print("h.defer()")
fmt.Println("h.1")
panic("panic in h()")
fmt.Println("h.2")
}
有疑问加站长微信联系(非本文作者)