Go语言基础知识(一)简单入门

package main //第一行 定义了包名 必须在源文件中非注释的第一行指明这个文件属于哪个包;

//注意:每个Go应用程序都包含一个名为main的包 

import "fmt" //告诉Go编译器这个程序需要使用fmt包(的函数,或其他元素),其中fmt包实现了格式化IO的函数 

/* 
  func main()是程序开始执行的函数,main函数是每一个可执行程序所必须包含的;
  一般来说都是启动后第一个执行的函数(但是如果有init()函数则会先执行init()函数) 
*/ 

func main() { 
    a := 10 
    fmt.Println(a) 
} 

一、基础知识点

1、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为到处(就像面向对象语言中的public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(就像面向对象语言中的private);

2、’{’ 不能单独放在一行,必须要放在上一行代码的后面,否则运行时会产生错误;

3、相比于其他语言,Go语言多了一些在其他语言上并不常见的关键字,比如:chan、fallthrough、select、func等;

4、单个数据类型定义和初始化赋值的方法:
var age int = 10 或者 age := 10

注意:使用操作符:=虽然可以高效地创建一个新的变量,但是只能被用在函数体内,不可以用于全局变量的声明与赋值;

5、Go的匿名函数是一个闭包,闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含在代码块中,所以这些自由变量以及它们的引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域);

6、数组的函数传递规则:未定义长度的数组只能传给不限制数组长度的函数,定义了长度的数组只能传给限制了相同数组长度的函数;Go的数组是值语义,一个数组变量表示整个数组,它不是指向第一个元素的指针(不像C语言的数组),当一个数组变量被赋值或者被传递的时候,实际上会复制整个数组;

二、扩展知识点:

1、slice (切片)

切片是动态的数组,是一个数组片段的描述,它包含了指向数组的指针,片段的长度和容量(片段的最大长度);切片的零值为nil,对于切片的零值,len和cap都将返回0;

切片可以基于现有的切片或数组生成,切片的范围由两个由冒号分割的索引对应的半开区间指定;切片的长度是切片引用的元素数目,容量是底层数组的元素数目(从切片指针开始);

切片操作并不复制切片指向的元素,它创建一个新的切片并复用原来切片的底层数组,因此,通过一个新切片修改元素会影响到原始切片的对应元素;

slice和数组的区别:
(1)数组在声明的时候方括号写明了长度或者使用…自动计算长度,而切片在声明的时候方括号内没有任何字符;
(2)切片是引用类型,所以当引用改变其中元素的时,其他的所有引用都会改变该值,创建的方法是make(),而数组则是值类型,创建的方法是new();

slice的append()方法 :

向slice里面追加一个或者多个元素,返回一个和slice一样类型的slice;需要注意是:append方法改变slice所引用的内容,从而影响到引用同一数组的其他slice,但当slice中没有剩余空间即cap-len=0时,返回的slice数组指针将指向这个空间,而原数组的内容将保持不变,其它引用次数组的slice则不受影响;

2、map

map也是一种引用类型,如果两个map同时指向一个底层,那么一个改变,另一个也相应的改变;但是map和其他基本类型不同,它不是thread-safe,在多个goroutine存取的时候,必须使用mutex lock机制;

3、channel

chan用于流入流出数据,是一种引用类型,通常来说会有变量名和缓冲信道容量两个值的初始化,如果缓冲信道容量的大小没有复制,则默认为0,即无缓冲信道。

无缓冲的信道永远你不会存储数据,只负责数据的流通;从无缓冲信道取数据,必须要有数据流入才可以,否则当前线程阻塞;数据流入无缓冲信道,如果没有其他goroutine来拿走这个数据,那么当前线阻塞;因此,如果信道正有数据在流入,我们还要加入数据,或者信道干涩,我们一直向无数据流入的空信道取数据,则会引起死锁;

避免这个死锁的办法就是,在Go启动的所有goroutine里的非缓冲信道一定要有一个线里存数据,一个线里取数据;

另外,如果在make创建的时候定义了缓冲信道的容量大小,则可以先把流入的数据放在新道理,不必阻塞当前线而等待该数据取走;但是当缓冲信道达到满的状态的时候,就会表现出阻塞了,因此此时已经无法承载更多的数据,需要先拿走一些;

缓冲信道是FIFO,我们可以把缓冲信道看作为一个线程安全的队列;需要注意的是,所有的goroutine会在一个原生线程里面跑(也就是只用一个CPU核),并且在同一个原生线程里面,如果当前goroutine不发生阻塞,它是不会让出CPU时间给其他同线程的goroutines的,这是Go运行时对goroutine的调度;当一个goroutine发生阻塞,Go会自动地把与该goroutine处于同一系统线程的其他goroutines转移到另一个系统线程上去,以使这些goroutines不阻塞;

4、make()和new()的区别

new的作用是初始化一个指向类型的指针(* T),new(T)分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值;

make的作用是创建slice、map和channel,为他们初始化并返回引用(T);

5、延迟(defer)语句

比如在一个函数在return跳出钱需要关闭资源,那么只需要对关闭的操作进行defer操作,可以避免在每个return跳出的出口之前写重复的关闭操作;如果函数中添加了多个defer语句,当函数执行到最后的时候,这些defer语句会按照逆序执行(即后进先出模式)

6、匿名函数作为闭包可作为值

函数当做值的时候,它的类型就是所有拥有相同的参数,相同的返回值的一种类型。在函数中定义匿名函数作为闭包赋给对应的值的时候,匿名函数内部的变量在当前整个函数内不可见,只可在匿名函数内修改,增加匿名函数内的数值的保护性;
 

发布了622 篇原创文章 · 获赞 150 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/feizaoSYUACM/article/details/83476847