本文共 14632 字,大约阅读时间需要 48 分钟。
是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
(1)打开终端,cd ~(2)查看是否有.bash_profile文件: ls -all(3)有则跳过此步,没有则: 1)创建:touch .bash_profile 2)编辑:open -e .bash_profile 3)自定义GOPATH和GOBIN位置:export GOPATH=/Users/lwh/program/Goexport GOBIN=$GOPATH/binexport PATH=$PATH:$GOBIN(4)编译:source .bash_profile
终端输入以下命令。显示go运行所需的系统环境变量。
go env
Sublime Text3的gosublime这个插件目前不能用,但是可以在github上下载,相比起来vscode有智能提示所以采用vscode。
goland使用:
goland应该是最好用的,很少的配置,收费,不缺钱可以支持下正版。 i> 。 ii> 新建一个project,选择项目location。 如果go环境安装成功goroot可以选择。然后create项目。 在项目根目录创建directory:main。然后在其下方写一个新的程序:test.go。package mainimport ( "fmt")func main(){ fmt.Println("hello world")}
Control + shift + R运行即可。#
即创建GOPATH目录,并在GOPATH下建立三个目录:
bin:存放编译后生成的可执行文件(.exe)pkg:存放编译后生成的包文件(.a)src:存放项目源码(.go)
函数名首字母小写,表示private;
函数名首字母大写,表示public。运行期间不可改变值。
可以涉及计算,但每一个值必须是编译期就能获得。true、false、iota。
初值为0,作为常量组中常量个数的计数器。
const PI float32 = 3.1415926const PI = 3.1415926 //隐式类型常量定义(省略常量类型,根据赋值自动判断类型)const a,b,c = 1, "Go", 'c' //整型常量、字符串常量、字符常量 多个常量一起定义
枚举指一系列的常量。
const ( Sunday = iota //0 iota生成了从0开始自动增长的枚举值 Monday //1 后续的iota可以省略 Tuesday //2 ) const ( A = iota //iota每遇到一个const关键字,就重置为0 B ) fmt.Println(Sunday); //0 fmt.Println(Monday); //1 fmt.Println(Tuesday); //2 fmt.Println("-------"); fmt.Println(A); //0 fmt.Println(B); //1
运行期间可改变的值。
变量名是用来引用变量所存储数据的标识符,实际上代表变量在内存中的地址,可以使用&
获取。 var count int = 10 //格式为:var[variableType]var count = 10 //缺省count: = 10 //用:代替var的缺省
即初始化值。
类型 | 零值 |
---|---|
bool | false |
int、float、byte\rune | 0 |
complex | 0+0i |
string | “” |
pointer、function、interface、slice、channel、map | nil |
i> 以字母或下划线开始
ii> 由字母、数字、下划线组成 iii> 避免关键字 iv> 大小写区分为不同的变量取值范围:true | false。
进制(4种):
123 //十进制0123 //八进制 以0开头0x123 //十六进制 以0x开头1e3 //指数形式 由数字和e组成 1*(10^3) = 1000
有无符号整型:
int //有符号整型uint //无符号整型
精度控制整数:
类型 | 字节长度 | 取值范围 |
---|---|---|
int | 4/8 | 由操作系统决定。32位机:int32,64位机int64 |
int8 | 1 | -128~127 (- 2^ 7 ~ (2^ 7 -1) ) |
int 16 | 2 | - 2^ 15 ~ (2^ 15 -1) |
int 32 | 4 | - 2^ 31 ~ (2^ 31 -1) |
int 64 | 8 | - 2^ 63 ~ (2^ 63 -1) |
- | - | - |
uint | 4/8 | |
uint8 | 1 | -128~127 (- 2^ 8 ~ (2^ 7) ) |
uint 16 | 2 | …… |
uint 32 | 4 | …… |
uint 64 | 8 | …… |
本质是uint8的类型,使用效果完全一样。
使用该别名是为了增强代码的可读性,告知现在是进行字节处理。 主要作用:表示和存储ASCII码,即处理字符。字符以ASCII的形式存储到内存中。所以一个byte型数据直接输出就是uint8整数形式;也可以将对应的ASCII码转换成相应的字符。
Go语言处理Unicode时专门的数据类型,完全等价于int32。
使用该别名是为了增强代码的可读性,告知现在是进行Unicode字符处理。表示形式:
1.251.23e3
类型 | 字节长度 | 精确位数 |
---|---|---|
float32 32位浮点型 | 4 | 精确到小数点后7位 |
float64 64位浮点型 | 8 | 精确到小数点后15位 |
浮点数存在舍入误差,所以避免极大数和极小数相加减丢失极小数。
var cp complex64 = 1.2 + 3.4i //复数:a+bi形式的数(i = 根号-1)。real(cp) //即1.2,fmt内置包计算实部的函数imag(cp) //即3.4,fmt内置包计算虚部的函数
类型 | 字节长度 |
---|---|
complex64 | 8 |
complex128 | 16 |
uintptr是可以保存指针的无符号整数类型,可以保存32位或64位的指针。根据操作系统决定指针位数。
//一般表现形式:var <指针变量名> * <基类型> var i_pointer * int //指向整型的变量的指针i_pointervar i int = 100; i_pointer = &i //将i的内存地址存放到i_pointer中fmt.Println( * i_pointer ) //通过指针i_pointer读取对应地址存放的数据,结果输出为100。 基类型> 指针变量名>
使用注意:
→
运算符,直接用.
选择符操作指针对象成员。包括:bool、int、float、byte、复数型(complex)、字符串(string)、数组、结构体、错误类型(error)。
值拷贝传递。 字符串(string)、数组、结构体又称为构造类型。包括:指针、切片(slice)、字典(map)、通道(channel)、接口(interface)、函数(function)。
var str string = "hello"; //字符串初始化 fmt.Println(str[2]); //取字符,以0开始。'A' = 65,'a' = 97, 输出为l = 97+12 = 108 fmt.Println(len(str)); //len()函数 输出为5 fmt.Println(str + " world");
支持2种方式。
var str string = "hello"; //字节数组方式遍历:(每一个字符类型为byte) for i := 0; i < len(str); i++ { fmt.Printf("str[%d] = %v\n", i, str[i]); } fmt.Println("-----------"); //Unicode字符方式遍历:(每一个字符类型为rune) for i, ch := range str { fmt.Printf("str[%d] = %v\n", i, ch); }
Go标准库包。
包含了字符串查找函数、字符串比较函数、字符串位置索引函数、字符串追加和替换函数Go标准库包。
提供了字符串与基本数据类型相互转化的基本函数。数组是一组具有相同类型和名称的变量的集合。
var arr1 [5] int
数组的元素类型必须是基本数据类型。
var arr1 = [2] int {1,2} var arr2 = [2] int {1} var arr3 = [...] int {2,2} //...就是三个英文句号。这个不能省略,否则就成切片了
var a[3][4] int //二维数组定义var a = [3][4] int { {1,2,3}, {4,5}, {6}}
是数组的一个引用,它会生成一个指向数组的指针,并通过切片长度关联到底层数组部分或者全部元素。
切片还提供了一系列对数组的管理功能,可以随时动态的扩充存储空间,并且可以被随意传递而不会导致所管理的数组元素被重复赋值。 故切片通常用于实现变长数组。type slice struct { array unsafe.Pointer //Pointer 是指向一个数组的指针 len int //len 代表当前切片的长度 cap int //cap 是当前切片的容量。cap 总是大于等于 len 的 }
var slice1 [] int //不要指定数组长度即切片
默认为nil,长度为0.
var slice1 = [] int {1,2,3,4}var slice1 = make([] int, 4) //通过内置函数make创建有4个元素的整型切片,元素初始值为int的初始值0.var slice1 = make([]int, 4, 10) //预留10个元素的存储空间。
slice1 = array1 //指定切片引用范围为数组全部slice1 = array1[ : ] //指定切片引用范围从第一个元素到最后一个元素slice1 = array1[m:n] //指定切片引用范围从第m个元素到第n个元素
由键值对组成。
未初始化时值为nil。
var map1 map[string] int {} //创建并初始化。键用[]包起来。map1["key1"] = 1
或者用make函数
var map1 map[string] int //创建map1 = make( map[string] int) //初始化,给map1分配存储空间
查找:
var map1 = map[string]int{"key1": 100, "key2": 200} v, OK := map1["key1"] //查找一个特定的键值对。如果key值存在,则将Key对应的Value值赋予v,OK为true。否则v=0,OK为false。 if OK { fmt.Println(v, OK) //输出:100 true } else { fmt.Println(v) }
删除:
delete(map1,"key1")
使用type关键字为类型定义别名。
type( word uint //定义word是uint的别名 小数 float32 //Go支持UTF-8编程格式,所以定义时可用非英文字符。 ) var f 小数 = 3.14 var i word = 3 fmt.Println(f) fmt.Println(i)
格式:<变量A>[:] = <变量A的类型>(<变量B>)
var a int var f float32 = 3.14 a = int(f) //如果变量A已经定义过了,可以省略`:` b := int(f) fmt.Println(a) fmt.Println(b)
用分号来终止语句,但这个分号可以由词法分析器扫描源代码过程中自动插入(给每一行末尾根据简单的规则进行判断是否需要加分号,所以出现了左大括号约定)。
//或/* */
运算符 | 描述 | 说明 |
---|---|---|
^ | 取反 | |
& | ||
| | ||
&^ | 标志位清除运算符 | 从a上清除b上的标志位 |
<< | 左移 | |
>> |
var a, b byte = 10, 4 //1010 fmt.Println(a) //10b fmt.Println(^a) //11110101b 2^8-1-10 = 256-11 = 245 fmt.Println(a &^ b) //1010b 清除 10b = 1000b = 8 ;1010b 清除 100b = 不变 = 1010b = 10 fmt.Println(a << 1) //10*2 = 20
详细用法可见通道。
原型:func Printf( format string, a...interface{} ) (n int, err error)
作用对象 | 格式字符 | 说明 |
---|---|---|
- | %v | 以基本格式输出 |
- | %#v | 输出数据,同时也输出Go语法表示 |
- | %T | 输出数据类型 |
- | %% | 输出% |
bool | %t | 输出布尔值true flase |
int | %b、%d、%o、%x、%X | 以二进制、十进制、八进制、十六进制(小写)、十六进制(大写) 输出 |
int | %c | 以Unicode字符格式输出(否则直接输出为ASCII码) |
int | %q | 输出的每个字符自动加单引号 |
int | %U | Unicode格式:U+1234 == U+%04X |
浮点型、复数 | %b | 无小数部分、两位指数的科学记数法 |
浮点型、复数 | %e、%E | 科学计数法(小写e、大写E) |
浮点型、复数 | %f | 有小数部分,但无指数部分 |
浮点型、复数 | %g、%G | 根据实际情况采用%e(%E)或%f |
字符串、切片 | %s | 直接输出字符串或切片 |
字符串、切片 | %q | 输出字符串的同时加双引号 |
字符串、切片 | %x、%X | 每个字节用两字符的十六进制数表示 |
指针 | %p | 以0x开头的十六进制数表示 |
- | + | 输出数值正负号对%q(%+q)按ASCII码输出 |
- | - | 使用空格填充右侧空缺(默认为左侧) |
- | # | |
- | ‘ ’ | |
- | 0 | 用前置0代替空格填补空缺 |
fmt.Printf("str[%d] = %v\n", i, str[i]);
原型:
func Scan(a ...interface{} )( n int, err error )
将使用空格分割的连续数据顺序存入到参数中(换行也被视为空格)。返回参数的数量n。
var a,b,c int fmt.Scan(&a,&b,&c)
原型:
func Scanln(a ...interface{} ) ( n int, err error)
同Scan,不同的是Scanln读取到换行符才终止录入。
原型:
func Scanf( format string, a ...interface{} )( n int, err error}
按照格式化字符读取数据。
var a,b,c int fmt.Scanf("%d,%d %d",&a,&b,&c) //严格按照格式输入才可以读取,如‘1,2 3’ fmt.Print(a) fmt.Print(b) fmt.Print(c)
用花括号{}
将多条语句组合在一起。
if 表达式1 {} else if 表达式2 {} else
注意:if语句块中不允许执行return语句。
switch 条件表达式 {case 常量1: 语句1 ……default: 语句n}或者:switch{case 条件表达1: 语句1 ……default: 语句n}
注意:
1>case语句后面不需要break,执行完自动跳出switch语句。 2>如果想执行完当前case后,继续执行下一个case,在case块最后面添加语句:fallthrough
var op byte = '+'; switch op { case '+': fmt.Println(1); fallthrough case '-': fmt.Println(2) }
只有for循环,没有do和while循环。
注意for语句后面没有括号。好的编程习惯:
var str string = "hello"; for i := 0; i < len(str); i++ { fmt.Printf("str[%d] = %v\n", i, str[i]); }
执行顺序:表达式1,表达式2,表达式4,表达式3
for 表达式1; 表达式2; 表达式3 { 表达式4}
类似while循环。
for 条件表达式{}
用break跳出循环。
for{}for true{}for ; ; {}
相当于迭代器,可以对数组(Array)、切片(Slice)、字典(Map)、通道(Channel)等进行遍历。在遍历时会返回一个键值对。
var str string = "hello"; for i, ch := range str { //返回的键值对i,ch i为下标,ch为值。 fmt.Printf("str[%d] = %v\n", i, ch); }
可以使用占位符过滤掉不需要数据。
for _,ch := range str{} //只需要值不需要键for i, _ := range str {} //只需要键不需要值for i := range str {} //只需要键不需要值
与LABEL搭配使用。
var a int = 1; goto LABEL1 a++ LABEL1: fmt.Println(a);
包是组成的Go程序的基本单位。每个Go源代码都要进行包声明说明当前文件属于哪个包。
package
可执行Go程序有且仅有一个main包,有且仅有一个main函数(在main包中)。
源码编译后都会生成*.a文件。分为如下三种模式。导入的包没有使用编译会报错(保证代码体积小,加快编译速度)。
import
举例:
import "fmt" //导入包fmt.Println(v, OK) //输出:100 true //包内函数调用
包名相近或相同用别名区分。
import 别名
import .
func为关键字。允许多返回值。
func funcName(参数列表)(返回值列表){ return result1, result2}
main函数没有参数也没有返回值,如果要传入参数,可在os.Args变量中保存。
任意数量:
func main() { a(1,2,3,4,5);}func a(args ... int){ fmt.Println(args) //输出[1 2 3 4 5] fmt.Println(args[2:]) //输出[3 4 5] 从索引2开始的数字}
任意类型的变参,类型指定为空接口interface{}:
func main() { a(1,2,"s",4,5);}func a(args ... interface{}){ fmt.Println(args) //输出[1 2 s 4 5]}
内部函数通过某种方式使其可见范围超出了其定义范围。
在go语言中,闭包可以作为函数对象或匿名函数。确保只要闭包还被使用,那么被闭包引用的变量会一直存在。通过defer向函数注册退出调用,当主调函数退出时,defer后的函数才会被执行(不管是否出现异常都会被执行)。
defer fmt.Println("defer ") fmt.Println("main ")
输出:
main deferfor i:=0; i<4; i++{ defer fmt.Println(i) }
输出:3210
func main() { fmt.Println("f1 = ",f1()) fmt.Println("f2 = ",f2())}//一个延迟执行的函数的变量的值在声明时,值不延迟func f1() int{ var i int defer fmt.Println(i) i = 1 return 1}//被延迟的匿名函数会读取f2的返回值,或对f2的返回值赋值func f2()(i int){ defer func(){ i++ }() return 1}
defer语句常用来进行函数的清理、释放资源等工作。
srcFile,err := os.Open("myFile")defer srcFile.Close
Go没有类的概念,通过结构体来实现面向对象编程。
type date struct {//定义 year int}type student struct { id int name string birthday date}func main() { stu := new(student) stu.name = "a" //访问 stu.id = 0 stu.birthday.year = 5 fmt.Println(stu)}
stu := student{0,"a",date{1}} //对象初始化
在普通的函数名前增加绑定类型参数。
type student struct { id int name string fee int}type teacher struct { id int name string fee int}func main() { stu := student{0,"a",10} t1 := teacher{0,"a",10} fmt.Println(stu.getFee()) fmt.Println(t1.getFee())}func (revc student) getFee() int{ //rev为变量,student为struct类型。 return 10+100}func (revc teacher) getFee() int{ //类似java中的多态。接收类型不同,方法名可以一样 return 10+1000}
如果指针作为一个receiver,那么是一个引用传递。
type people struct { id int name string fee int}type student struct { people school string}func main() { stu := student{people{0,"a",10},"ut"} fmt.Println(stu.getFee())}func (revc student) getFee() int{ //重写了方法,隐藏了people的getFee方法 return 10+100}func (revc people) getFee() int{ return 10+1000}
是一组Method的组合,通过Interface来定义对象的一组行为。
type Speaker interface { //关键字:type interface sayHi()}func (s student)sayHi(){ }func (s student)study(){}
集合其他接口的功能
type SpeakerLearner interface { Speaker study()}
表示任何数据类型。
interface{}
是format缩写。内置基本包。
Package fmt implements formatted I/O with functions analogous to C’s printf and scanf. The format ‘verbs’ are derived from C’s but are simpler.
Max(int8) Min(int8) //数据的最大值最小值
提供了对字节切片进行读写操作的一系列函数和方法。包括:字节切片处理函数、Buffer对象和Reader对象,类似于strings包。
实现了对数据I/O接口的缓冲功能。
封装于接口io.ReadWriter、io.Reader和io.Writer中,在提供缓冲的同时实现了一些文本的基本I/O操作功能。UTF-8格式。
标记-清除算法。
GO有两种分配内存机制,分别是使用内置函数new()和make()。
用于给值类型的数据分配内存,调用成功后返回一个初始化的内存块指针,同时该类型被初始化为“0”.
用于给引用类型分配内存空间。
make函数创建的是一个引用类型对象,而不是一个内存空间的指针。进程、
线程、 协程(用户态线程):不需要OS进行抢占式调度,在真正的实现中寄存于线程。是Go语言运行库的功能(由Go运行时管理(Runtime)),不是OS提供的功能(不是用线程实现的,所以支持跨平台)。
Goroutine就是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈。因为节省了频繁创建和销毁线程的开销,所以对于进程、线程的开销非常小。可以轻松创建上百万个Goroutine,但它们不是被OS所调度执行的。 Go语言标准库提供的所有系统调用操作(包括同步I/O操作),都会让出处理机给其他Goroutine。通过关键字go来创建并发执行的Goroutine。
基本格式:go func()
import ( "fmt" "math/rand")func Test(ch chan int){ ch <- rand.Int() //随机数获取并写入 fmt.Println("Test")}func main() { chs := make([]chan int , 10) //定义一个包含10个Channel的数组chs for i:=0;i<10;i++{ chs[i] = make(chan int) go Test(chs[i]) //启动10个Goroutine,对应每一个Goroutin分配一个Channel } for _,ch := range chs{ value := <-ch //从通道读取数据 fmt.Println(value) } fmt.Println("main") //因为通道的写入和读取都是阻塞的,从而保证了即使没有锁,所有的Goroutin执行完后才main才返回。即:main总是在最后输出的。}
是Go提供的消息通信机制。主要用于并发通信,类似于单双向数据管道(Pipe),用户可以通过Channel在两个或多个Goroutine之间传递消息。
注意:
Channel是引用类型,一个Channel只能传递一种类型的值,这个类型需要在声明Channel时指定。
支持的类型:基本类型、指针、Array、Slice、Mapvar chanName chan ElementTypevar ch chan int //一个传递int类型的Channel。chan为关键字。ch := make(chan int) //用make函数直接声明
ch < - value //通道接收数据。ch表示通道,value表示数据。value = < - ch //通道发送数据
注意:
3. 向Channel写入数据通常会导致程序阻塞,直到有其他Goroutine从这个Channel中读取数据。 4. 如果Channel中之前没有写入数据,那么从Channel中读取数据也会导致阻塞,直到Channel中被写入数据为止。throw : all goroutines are asleep-deadlock!
声明时可以将Chanel制定为单向通道:只能接收或只能发送。
var chanName chan <- ElementType //只能接收var chanName <- chan ElementType //只能发送
给Channel设定一个Buffer值,用于持续传输大量数据。
在Buffer未写满之前,不阻塞发送操作(即使没有读取方,发送方也不断写入数据); 在Buffer未读完之前,不阻塞接收操作。ch := make(chan int, 1024) //创建一个大小为1024的int类型Channel。
主要用于解决通道通信中的多路复用问题。
select语句(类似switch):
select{ case <- chan1: //如果 chan1 成功读取数据,则进行该case处理语句 case <- chan2: …… default:}
select直接检测case语句,每个case语句必须是一个面向Channel的操作.
只要其中一个case完成,程序就会继续向下执行。利用这个特性可以可以为Channe实现超时处理功能。由于通道的接收是阻塞式的,为了将阻塞式的通信转换为非阻塞式,将select机制和超时机制配合使用,以提高系统通信效率。
在Go语言并发编程的通信过程中,所有错误处理都由超时机制来完成。 超时机制一般用来解决通信死锁,通常设置一个超时参数,通信双方如果在设定的时间内仍然没处理完成任务,则该处理过程会立即被终止,并返回对应的超时信息。 Go没有提供直接的超时处理机制。利用select机制可以实现。传统的Socket网络编程分为:流式套接字(基于TCP)、数据报套接字(基于UDP)、原始式套接字(基于IP)。
Go语言对socket进行了封装,无论期望用什么协议都只需要调用Dial函数即可。
支持网络协议:tcp、tcp4、tcp6、udp、udp4、udp6、ip、ip4、ip6。 创建连接:func Dial ( net, addr string) (Conn, error) //net是网络协议名,addr是IP地址或域名,后面可跟随端口号。conn,err := net.Dial ("tcp", "192.168.0.1:5000")conn,err := net.Dial ("ip4:icmp", "www.baidu.com")
发送数据:使用conn对象的Write()方法
接收数据:使用conn对象的Read()方法转载地址:http://ouqt.baihongyu.com/