Go语言实现HTTP压测工具(2)——Golang语言基础学习和使用 - Go语言中文社区

Go语言实现HTTP压测工具(2)——Golang语言基础学习和使用


0 前言

一周之内要完成的任务。
在这里插入图片描述
本文目前不做过多的知识介绍,一是因为赶时间完成任务,二是对于有编程基础的人来说,不用事无巨细的都记下来,只要学学该语言的设计思想,总结一下其特别的地方和用法,差不多就入门了。

但是这篇文章开在这里,留给以后在学习使用Go语言时,记录一些不会的基础的知识。

参考资料:
《Go入门经典》,【英】乔治·奥尔波
Go 入门指南 - GitHub
刘鹏杰 / golang-看云

1. 数据类型


2. 函数


1. 函数结构

func func_name(s string, a int) (int, int) {   # 这一行是函数签名

}

2. 不定参函数

// 计算任意多个整数的和并返回
func sumNumbers(nums...int) int {
	total := 0
	for _, x := range nums {
		total += x
	}
	return total
]

这里的变量nums就是一个包含所有参数的切片,可以看做一个包含所有待累加的数字组成的整型数组吧,因为长度不定,所以用三个点...代表。

3. 具名返回值

4. 将函数作为值传递

本质上,Go将函数视为一种类型,因此可将函数赋给变量

func main() {
	fn := func() {
		fmt.Println("xxx")
	}
	fn()
}

既然函数是一种类型,可以赋给变量,那么,也可以作为参数,再传给其它函数


func anoFunc(t func() string) string {
	return t()
}

func main() {
	fn := func() string {
		return "xxx"
	}
	fmt.Println(anoFunc(fn))
}

有一点要注意,就是参数中,函数的返回类型,要与接收函数的参数类型一致,这很好理解,就像MR中,Map的输出格式肯定是和Reduce的输入格式一样的,不然怎么对接的上。

5. 其它地方

  1. 函数声明后,编译器就记录了其签名,并根据签名,检查调用时该函数的参数数量和类型是否正确;

  2. 不允许函数重载(overload);

3. 控制结构


3.1 for range用法

有点像for each用法,这个for range返回其角标和值

for pos, char := range nums {
	// pos = [0, 1, 2,...]
	// char = [values1, values2,...]
}
3.2 defer用法

用于在外部函数都运行结束后,再运行的语句。一些应用场景如:在读取文件后将其关闭,需要在某项工作完成后,执行特定的函数时使用。如果有多条defer语句,则按照出现顺序相反的来执行。

4. 数组、切片(Slice)与映射(Map)


数组
定义var nums [n]int,定义后长度不可变,有局限性。

切片
定义var sb = make([]string, 2),定义了一个长度为2,参数为字符串类型的切片,并赋值给变量sb。可以使用append进行操作。

// 1. 添加

// 2. 删除

// 3. 复制

映射
定义var age = make(map [string] int),键值对集合。可以动态调整元素。
删除时使用delete(age,"key")

注意,delete方法不能用户切片和数组,没有专门用于从切片中删除元素的函数,用内置函数append来完成。

5. 结构体(Struct)与方法(Method)


5.1 结构体创建方式
type Movie sruct {
	Name 	string
	Rating	float32
}

// 1. 变量声明方式
var m Movie
m.Name = "xxx"
m.Rating = 0.99

// 2.关键字 new
m := new(Movie)
m.Name = "xx"
m.Rating = 0.99


// 3. 简短变量赋值方式和
m := Movie{
	Name: "xxx",
	Rating: 0.99,
}

简短赋值方式中的逗号别忘了写

5.2 方法

定义方式

func (recv receive_type) methodName(parameter_list) return_value_list {
	// your code
}

Go中的方法集可以与任何类型相关联(切片等),能够在数据类型和方法之间建立关系。

函数和方法的区别
函数将变量作为参数:Function1(recv)
方法在变量上被调用:recv.Method1()
在接收者是指针时,方法可以改变接收者的值(或状态),这点函数也可以做到(当参数作为指针传递,即通过引用调用时,函数也可以改变参数的状态)。
接收者必须有一个显式的名字,这个名字必须在方法中被使用。
receiver_type 叫做 (接收者)基本类型,这个类型必须在和方法同样的包中被声明。
在 Go 中,(接收者)类型关联的方法不写在类型结构里面,就像类那样;耦合更加宽松;类型和方法之间的关联由接收者来建立。

个人理解,结构体本质上是一种模型,数据模型,虽然书上说,结构体并非创建面向对象代码的方式,而是一种数据结构创建方式,旨在满足数据建模需求。但对于我这个初学者来说,就是会把其理解为面向对象中的类,然后对其进行不同的实例化。

在Java中,基本数据类型是按值传递,引用数据类型(数组,接口,类)按值传递的时候都是传递对象的地址(可以参考我的另一篇博客 Java基础知识补充,不定时更新)。

Go 默认使用按值传递来传递参数,也就是传递参数的副本。函数接收参数副本之后,在使用变量的过程中可能对副本的值进行更改,但不会影响到原来的变量,比如 Function(arg1)。

如果你希望函数可以直接修改参数的值,而不是对参数的副本进行操作,你需要将参数的地址(变量名前面添加&符号,比如 &variable)传递给函数,这就是按引用传递,比如 Function(&arg1),此时传递给函数的是一个指针。

6. 协程(Goroutine)和通道(Channel)


这应该才是Go最具特色的地方吧

Concurrency is not parallelism

我就先不在这说了, 怕误导了大家,先放几个参考博文

Go语言实战笔记(十二)| Go goroutine
Go语言并发与并行学习笔记(一)
图解 Go 并发编程-中文
Learning Go’s Concurrency Through Illustrations-English

7. 命令行参数

稍微具体一点的在我的周报中写了 周报 2019-06-16 @W24

在这补充一些。

7.1 os.Args[]
7.2 flag包

参考来源
1. 13.1 flag - 命令行参数解析

关于Nflag函数
在这里插入图片描述

上面可以看到,args的内容一直是空的,我倒要来看看这个咋出来的。

在这里插入图片描述

结合参考文章说一下,这个args是一种non-flag,也就是说,在命令行上输入的字符,但是不是flag中设置的参数,比如上面的前两个 1,和 build 1。

最后一个呢,可以看到有点不一样的地方,它把--1当作flag中的参数-1,而且,把后面的2--当作该参数的值了!

x. 一些小地方


首字母大写

有个特别的地方,首字母大写,权限就相当于Public,而骆驼命名法,则权限默认为Protected

目前看来,函数名、结构体及其字段名都是这样。

有意思的下划线_

这里面有个短下划线_,最开始定义是说忽略的作用,当时是有点懵的,啥叫忽略,现在明白了。

可以用在几个地方

  1. 代码中作为占位符或者丢弃返回值

举个例子吧。

// 1. 正常操作
func main() {
	f, err := ioutil.ReadFile("readme.txt")
	// code...
}

但是如果我不关心文件内容,只关心这个文件有没有读取成功呢?也就是说,我不要 f 变量,只要对 err 进行判断一下,在Go语言中,如果有变量未被使用,会提示,讲究的就是每个代码都有用,没有多余的代码,那么这时候,就可以用下划线了。

// 2. 丢弃返回的 f
func main() {
	_, err := ioutil.ReadFile("readme.txt")
	// code...
}

这样,就可以了,依然是返回两个变量,但是将上面的 f 赋给了下划线,就会被忽略,也不会引起程序报错。

但是我有个疑问,这样会开辟内存空间么?不会造成浪费么?

  1. 导包时

在导包时,有时候不需要导入整个包,只要调用一下其 init() 函数就行了,这时候也是用下划线实现,它会调用该包下所有的 init() 函数,但不导入整个包。

import "database/sql"
import _ "github.com/go-sql-driver/mysql"

这样就会执行mysql包中的初始化函数,将mysql驱动注册到sql中,但不会导入mysql包,并且后面就可以在sql包中操作mysql数据库。

几种变量声明方式

Go语言提供了多种变量声明方式

1. 指定类型并赋值
var s string = "hello,world!"

2. 省略类型并赋值
var s =  "hello,world!"

3. 先声明类型,后赋值
var t string
t =  "hello,world!"

4. 简短变量声明
u :=  "hello,world!"

是不是有点懵,所以,我们到底应该用哪种呢?(以下摘自《Go语言入门经典》P23)

Go语言设计者在标准库中遵循的约定如下:在函数内使用简短变量声明,在函数外省略类型。且Go源码中,简短变量声明是最常用的。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_41059320/article/details/91350996
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢