2022-5-11 实习Day33

1、测试环境基础配置数据导出 – 1小时 100%
2、202报文发起汇入汇款交易解付完成未发出gpi299报文排查 –2小时 50%
3、核心记账失败,机构内部账类型在测试环境中没有找到。–2小时 100%

Golang编程学习(part 28)

1、方法的声明(和函数是两回事)

比如Person结构体除了有一些字段外(年龄、姓名、…),Person结构体还有一些行为,比如:可以说话、跑步…,这就要用方法才能完成。
Golang中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型都可以有方法,而不仅仅是struct
1
2
3
4
5
6
7
8
9
10
11
12
type A struct {
Num int
}

func (a A) test() {
fmt.Println(a.Num)
}

func main() {
var a = A{10}
a.test()
}
对上面的语法的说明:

1)func (a A) test() {} 表示A结构体有一个方法,方法名为test

2)(a A)体现了test方法是和A类型绑定的【只能通过A类型来调用,不能直接调用或使用其他类型变量来调用】

3)func (a A) test() {}中的a表示哪个Person变量调用,这个a就是它的副本,这点和函数传参非常相似。

4)a这个名字由程序员自己指定,不是固定,比如修改成aaa也是可以的

2、方法的调用和传参机制原理(重要!!!)

① 方法的调用、传参机制和函数基本一样,不一样的地方是方法调用时会将调用方法的变量当作实参也传递给方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
type Person struct {
Name string
Age int
Sex bool
}

func (p Person) getSum(n1 int, n2 int) int {
return n1 + n2
}

func main() {
var p1 Person
p1.Name = "张三"
p1.Age = 20
p1.Sex = true
n1 := 10
n2 := 20

sum := p1.getSum(n1, n2)
fmt.Println(sum)
}

画图
-------------------------------------|
| getSum栈 |
| n1 ----> [10] |
| n2 ----> [20] |
| p ----> [ "张三" | 20 | true ] |
| return 30 |
|____________________________________|
| main栈 |
| p ----> [ "张三" | 20 | true ] |
| n1 ----> [10] |
| n2 ----> [20] |
| sum = 30 |
|___________________________________|

说明:

1)在通过一个变量去调用方法时,其调用机制和函数一样

2)不一样的地方是,变量调用方法时,该变量本身也会作为一个参数传递到方法中【如果变量是值类型,则进行拷贝,如果变量是引用类型,则进行地址拷贝】

3、方法的注意事项和细节

① 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
② 如果程序员程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
type Circle struct {
radius float64
}

// 为了提高效率,通常我们方法和结构体的指针类型绑定
func (c *Circle) Compute() float64 {
// 因为c是指针,因此我们标准的访问方式为(*c).radius
// 但这边 (*c).radius等价c.radius
c.radius = 20
return c.radius * c.radius * math.Pi
}

func main() {
var c1 = Circle{16}
// 编译底层做了优化 (&c1).Compute() 等价于 c1.Compute()
// 因为编译器会自动加上 &c1
res := c1.Compute()
fmt.Println("面积=", res)

fmt.Println("c1.radius = ", (&c1).radius)
}

面积= 1256.6370614359173
c1.radius = 20

③ Golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型都可以有方法,而不仅仅是struct,比如 int,float32 等都可以有方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type integer int

func (i integer) print() {
fmt.Println("i=",i)
}

// 编写一个方法,可以改变i的值
func (i *integer) change() {
*i = *i + 1
}

func main() {
var i integer = 10
i.print()
i.change()
fmt.Println("i=",i) // 11
}
④ 方法的访问权限的规则和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问
⑤ 如果一个类型实现了 String() 这个方法,那么fmt.Println默认会调用这个变量的String()进行输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Student struct {
Name string
Age int
}

// 给*Student实现方法String()
func (stu *Student) String() string {
str := fmt.Sprintf("Name=%v,Age=%v", (*stu).Name, (*stu).Age)
return str
}
func main() {
stu := Student{Name: "张三", Age: 25}
// 如果你实现了 *Student 类型的String方法,就会自动调用
fmt.Println(&stu) // Name=张三,Age=25
}

4、方法和函数的区别

① 调用方式不一样:函数 ——> 函数名(实参列表) 方法 ——> 方法名(实参列表)
② 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
③ 对于方法(如struct方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反之同样可以
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
type Person struct {
Name string
}

func (p Person) test1() {
p.Name = "jack"
fmt.Println("test1()=", p.Name)
}
func (p *Person) test2() {
p.Name = "mary"
fmt.Println("test2=", p.Name)
}
func main() {
var p Person
p.test1()
fmt.Println(p.Name)
// 从形式上是传入地址,但是本质仍然是值拷贝
(&p).test1()
fmt.Println(p.Name)

(&p).test2()
fmt.Println(p.Name)
p.test2()
fmt.Println(p.Name)
}

test1()= jack

test1()= jack

test2= mary
mary
test2= mary
mary

总结:

1)不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和哪个类型绑定
2)如果是值类型,比如 (p Person),则是值拷贝。如果是指针类型,比如是 (p *Person),则是地址拷贝。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//课堂练习: 编写方法,将数组转置
type Trang struct {
row int
column int
slice [][]int
}

func (receiver *Trang) zhuanzhi() {
tran := *receiver
arr := make([][]int, tran.row)
for i := 0; i < tran.column; i++ {
arr[i] = make([]int, tran.column)
for j := 0; j < tran.row; j++ {
arr[i][j] = tran.slice[j][i]
}
}
for _, v := range arr {
fmt.Println(v)
}
}
func main() {
tran := Trang{3, 3, nil}
tran.slice =
[][]int{
{1, 8, 9},
{8, 4, 6},
{7, 5, 2}}
tran.zhuanzhi()
}