Golang 入门-基础类型&函数定义篇

在上一篇文章中讲述了配置与输出,接下来我们进入下一步的学习

前言:Go语言特性

Go语言是Google公司开发的一种静态的,编译型并自带垃圾回收和并发的变成语言.
Go语言的风格类似C语言,其语法在C语言的基础上进行了大幅度的优化,去掉了不需要的表达式括号,循环也只有for一种表示方法,就可以实现数值,键值等各种遍历.因此, Go语言上手非常容易.
Go语言最具有特色的特性莫过于goroutine. Go语言在语言层可以通过goroutine对函数实现并发并行. goroutine类似于线程,但并非线程, goroutine会在Go语言运行时进行自动调度.因此,Go语言非常适合用于高并发网络服务的编写.

一、Go的基本语法以及使用

1、整型类型

Go对类型的长度有极大要求
长度类型:int8 int16 int32 int64
对应无符号类型:uint8 uint16 uint32 uint64

2、浮点型

Go语言支持两种浮点整数:
float32:最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32
float64:最大范围约为 1.8e308,可以使用常量定义:math.MaxFloat64

3、布尔型

布尔型数据只有true和false
Go语言中不允许将整型强制转换为布尔型,代码如下:
fmt.Println(int(n) * 2)
编译错误,输出如下:
cannot convert n (type bool) to type int
布尔型无法参与数值运算,也无法与其他类型进行转换

4、字符串型

对于字符串类型,以双引号为扩住的则为字符串类型,可放入非ASCII码的字符

str := "hello world"
ch  := "中文"

5、切片

接下来讲述Go语言中的切片(能够动态的的分配空间)是一个拥有相同类型元素的可变长度序列

var arr[]类型    // 初始化的时候定义,后面追加上类型 如int string float等
例:var arr[]int

切片的元素使用”[]“来进行访问,在[]里提供数值索引可获取相对应的value值,切片的索引默认访问是从0开始,如赋值时没有从对应数字开始则默认值会自定义为0,以下贴上代码

// 创建切片
item := make([]int, 3)	//创建一个容量为3的整型切片 ps:其实就是创建一个容量只能为3的切片,但是value都只能为int
item[0] = 0		//为切片元素赋值
item[1] = 1
item[2] = 2

fmt.Println(item)
输出:[0 1 2]

如不按顺序来进行赋值

// 创建切片
item := make([]int, 10)	//创建一个容量为10的整型切片 ps:其实就是创建一个容量只能为10的切片,但是value都只能为int
item[7] = 77
item[8] = 88

fmt.Println(item)
输出:[0 0 0 0 0 0 0 77 88 0]  // 未定义的索引值则默认为0

我们也可以进行切片追加(append)

info := append(item, 99)

fmt.Println(item, info)
输出: [0 0 0 0 0 0 0 77 88 0 99]  // 在原来的基础上追加了99

替换覆盖(copy)

test := []int{1,2,3,4,5}
copy(info, test)

fmt.Println(info)
输出:[1 2 3 4 5 0 0 77 88 0 99]

字符串也可以按照切片的方式进行操作(字符串截取功能,从第1位开始数)

str := "hello world"
fmt.Println(str[6:])// 输出截取,这里注意的是截取只能截取字符串类型的,其他类型截不了
输出:world

以上是简单的一些小案例,还有更多的一些语法技巧函数,可上Go官方文档查看http://docscn.studygolang.com/doc/

二、变量

1、变量声明

var a int//声明一个整型类型的变量,可以保存整数数值
var b string//声明一个字符串类型的变量
var c []float32//声明一个32位浮点切片类型的变量,浮点切片表示由多个浮点类型组成的数据结构
var d func() bool//声明一个返回值为布尔类型的函数变量,这种形式一般用于回调函数,即将函数以变量的形式保存下来,在需要的时候重新调用这个函数
var e struct{//声明一个结构体变量,拥有一个整型的x字段
    x int
}

标准定义:var 参数名 类型

批量声明

var (
a int 
b string
c []float32
d func() bool
e struct{
    x int
    }
)

初始化变量(标准格式)

var 变量名 类型 = 表达式
例:小明考试考了100分
var score int = 100

初始化变量(短变量声明)

score := 100
// 如果score已经被var初始化过,则这个时候会报错,例如以下
var score int = 90
score := 80
// error : no new variables on left side of :=
// 报错提示的原因是左边没有新的变量名出现,则不允许重新赋值

// ps:也可以支持多个变量一直赋值
info, score, x = 0, 1, 2

2、匿名变量(没有名字并且不需要用到的变量,可减少内存空间)

在开发过程中,有时候调用某个方法后,发现一些参数是不需要的,但是又不想浪费内存去接收到,那么可以用”_“下划线进行代替

func item() (int,int) {
    return 100, 200
}
a, _ := item()
fmt.Println(a)

输出:100

// 当然,我们也可以在赋值的时候这么做

_, score := 0, 80
fmt.Println(score)

输出:80

Go在内存这方面还是很强大的,完全不用担心内存溢出,可以大胆放心使用

三、函数

函数的常规定义

func 方法名(参数列表) 返回值 {
    定义
}

例:

func item(a) int {
    return 100
}

1、函数的值(闭包)

函数值不仅仅是一串代码,还记录了状态。Go使用闭包(closures)技术实现函数值,Go程序员也把函数值叫做闭包。我们看个闭包的例子:

func f1(limit int) (func(v int) bool) {
    //编译器发现limit逃逸了,自动在堆上分配
    return func (v int) bool { return v > limit}
}
func main(){

    closure := f1(3)
    fmt.Printf("%v\n", closure(1)) //false
    fmt.Printf("%v\n", closure(3)) //false
    fmt.Printf("%v\n", closure(10)) //true
}

ps:程序执行流程

1、程序进入main后,发现调用了f1方法并带入了”3“,此时返回一个闭包
2、走到下面closure(1)时,程序发现有传入闭包值”1“
3、程序走进上面的方法内,此时limit = 3, 闭包内的v = 1
4、走到下面的逻辑判断中,引用闭包内的v,并且将v与limit做比较
5、最终得到结果,返回给下面的 fmt.Printf("%v\n", closure(1))进行输出
6、依次类推

函数可变参数

可变参数,即参数不是固定死的一个值,可以有无限N个,例如fmt.Printf函数那样, 但只有最后一个参数可设置为可变参数

声明

func 函数名(变量名...类型) 返回值

举例:

func getData(str string, vals... int) (num int) {
    for  _,v := range vals {
	num += v
    }
    num += len(str)
    return
}

func main(){
    fmt.Printf("%d\n", getData("abc", 1,2,3,4,5 )) 
}

输出:18


将传入的1,2,3,4,5 循环追加给num值,最后再加上str的长度 15 + 3 = 18
注意:在for后面一点要加上匿名函数,否则始终不会循环追加最后一个值,如去掉加起来则为13
getData第二个参数即最后一个参数则为可变参数

2、函数的延迟执行 defer

包含defer语句的函数执行完毕后(例如return、panic),释放堆栈前会调用被声明defer的语句,常用于释放资源、记录函数执行耗时等,有一下几个特点:

  • 当defer被声明时,其参数就会被实时解析
  • 执行顺序和声明顺序相反
  • defer可以读取有名返回值
//演示defer的函数可以访问返回值
func f2() (v int) {
    defer func (){ v++}()
    return 1 //执行这个时,把v置为1
}

//演示defer声明即解释
func f3(i int) (v int) {
    defer func(j int) {
	v+= j
    } (i) 		//此时函数i已被解析为10,后面修改i的值无影响
    v = 9		// v = 9
    i = i*2		// i = 20
    return
}

//演示defer的执行顺序,与声明顺序相反
func f4() {
    defer func() {fmt.Printf("first\n")} ()
    defer func() {fmt.Printf("second\n")} ()
}

func main(){
    fmt.Printf("%d\n", f2()) // 13
    fmt.Printf("%d\n", f3(10)) // 19
    f4() //second\nfirst\n

最终输出:
        2
        19
        second
        first

执行过程:
1、首先调用了f2,由于defer是在return执行后再去执行的,所以当return 1时,附加v++ 所以最终返回值为2
2、调用了f3并传入值为10,进入到f3方法中,v = 9,i = 20,走到defer,此时i已经被解析成了10,所以后面的相乘无影响
3、接着进入defer后,设定了j值,此时j = i = 10,v是后面新赋的值,也没有被解析,所以v+=j 则等于 v = 9+10 = 19,最后返回19
4、最后一步f4是返回的顺序是相反的,则验明了defer是在声明的倒序执行的

ps:一般典型的用来计算耗时,资源关闭等,相关操作可按照业务逻辑编写

Golang学习文章会持续更新,谢谢

 

发布了59 篇原创文章 · 获赞 219 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_34284638/article/details/104898402
今日推荐