社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
Go语言是Google公司开发的一种静态的,编译型并自带垃圾回收和并发的编程语言.Go语言的风格类似C语言,其语法在C语言的基础上进行了大幅度的优化,去掉了不需要的表达式括号。
Go语言最具有特色的特性莫过于goroutine. Go语言非常适合用于高并发网络服务的编写.
例如实现一个简单的HTTP服务器只需要几行代码
import (
"net/http"
)
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
http.ListenAndServe(":8080", nil)
}
go build ./helloworld.go
Go语言不仅可以输出可执行文件,还可以编译输出导入C语言的静态库,动态库.
同时从Go1.7版本开始, Go语言支持将代码编译为插件. 使用插件可以动态加载需要的模块, 而不是一次性将所有的代码编译为一个可执行文件.
Go语言的源码无需头文件,编译的文件都来自于后缀名为go的源码文件; Go语言无需解决方案,工程文件和Make File. 只要将工程文件按照GOPATH的规则进行填充,即可使用go build/go install 进行编译,编译安装的二进制可执行文件统一放在bin文件夹下.
Go语言的特性就是从语言层支持并发,无需第三方库,开发者的编程技巧及开发经验就可以轻松地在Go语言运行时来帮助开发者决定怎么使用CPU资源.
Go语言的并发是基于goroutine, goroutine类似于线程,但并非线程.可以将goroutine理解为一种虚拟线程.Go语言运行时会参与调度goroutine,并将goroutine合理地分配到每个CPU中,最大限度地使用CPU性能.
多个goroutine中,Go语言使用通道(channel)进行通信,程序可以将需要并发的程序设计为生产者和消费者的模式,将数据放入通道.通道的另外一端的代码将这些数据进行并发计算并返回结果.
下面代码中的生产者每秒生成一个字符串,并通过通道传给消费者,生产者使用两个goroutine并发运行,消费者在main()函数的goroutine中进行处理
package main
import (
"fmt"//导入格式化
"math/rand"//随机数
"time"//时间
)
//数据生产者
func producer(header string,channel chan <- string) {//生产数据的函数,传入一个标记类型为字符串及一个只能写入的通道
//无限循环,不停的生产数据
for {
//将随机数和字符串格式化为字符串发送通道
channel <- fmt.Sprintf("%s:%v",header,rand.Int31())
//等待一秒
time.Sleep(time.Second)
}
}
//数据消费者
func consumer(channel <- chan string) {
//不停的获取数据
for {
//从通道中取出数据,此处会阻塞直到信道中返回数据
message := <- channel
//打印数据
fmt.Println(message)
}
}
func main() {
//创建一个字符串类型的通道
channel := make(chan string)
//创建producer函数的并发goroutine(协成)
go producer("cat",channel)
go producer("dog",channel)
//数据消费函数
consumer(channel)
}
代码输出如下:
dog:140954425
cat:336122540
dog:208240456
cat:646203300
cat:1106410694
dog:1747278511
cat:817455089
dog:460128162
dog:683024728
cat:1006933274
cat:607811211
dog:629431445
整段代码中,没有线程创建,没有线程池也没有加锁,仅仅通过关键字Go实现goroutine,和通道实现数据交换.
安装Go语言开发包后,使用Go语言开发工具链可以直接进行Go代码的性能分析. Go的性能分析工具将性能数据以二进制文件输出,配合Graphviz即可将性能分析数据以图形化的方式展现出来, Go语言会用过图连接和数据告知每个执行步骤的耗时,较为耗时的流程执行框会变大.开发人员会根据这些直观的图表即可迅速定位问题代码的位置!
Go语言的标准库覆盖网络,系统,加密,编码,图形等各个方面,可以直接使用标准库的http包进行HTTP协议的收发处理;网络库基于高性能的操作系统通信模型(Linux的epoll,Windows的IOCP);所有的加密,编码都内建支持,不需要再从第三方开发者处获取.Go语言的编译器也是标准库的一部分,通过词法器扫描源码,使用语法树获得源码逻辑分支等.Go语言的周边工具也是建立在这些标准库上.在标准库上可以完成几乎大部分的需求.另外,Go语言的标准库以包的方式提供支持!
9.代码风格清晰,简单
Go语言写起来类似C语言,因此获悉C语言及其派生语言(C++,C#,Objective-C等)的人都会迅速熟悉这门语言.
1.去掉循环冗余括号
C语言
for (int a =0;a<10;a++) {
//循环代码
}
Go语言
for a:= 0; a<10;a++ {
//循环代码
}
2.去掉表达式冗余括号
if 表达式{
//表达式成立
}
3.强制的代码风格
Go语言中,左括号必须紧接着语句不换行.其他样式的括号将被视为代码编译错误.这个特性刚开始会使一些开发者有以下不习惯,但随着对Go语言的不断熟悉,开发者就会发现风格统一让大家在阅读代码时会把注意力集中到解决问题上,而不是代码风格上.
同时Go语言也提供了一套格式化工具.一些Go语言的开发环境或者编译器在保存时,都会使用格式化工具进行修改代码格式化,让代码提交时已经统一格式的代码.
4.不在纠结于i++和++i
C语言非常经典的考试题为:
int a, b;
a = i++;
b = ++i
这种题目对于初学者兼职摸不着头脑.为什么一个简单的自增表达式需要有两种写法?
在Go语言中,自增操作符不再是一个操作符,而是一个语句.因此,在Go语言中自增只有一种写法:
i++
如果写成前置自增"++i",或者赋值后自增"a=i++"都将导致编译错误!
go常用命令:
2.1:创建一个main.go
2.2:导入头文件
import "fmt"//导入格式化
func main() {//启动函数
fmt.Println("hello world")//打印hello world
}
go run 运行当个.go文件
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。
Go 语言的字符串可以通过 + 实现
Go 语言中变量的声明必须使用空格隔开,如:
var age int;
分为
按长度分为: int8 int16 int32 int64
还有对应的无符号整型:uint8 uint16 uint32 uint64
浮点型:
Go语言支持两种浮点整数:
float32:最大范围约为 3.4e38,可以使用常量定义:math.MaxFloat32
floa642:最大范围约为 1.8e308,可以使用常量定义:math.MaxFloat64
布尔型:
只有true和false
Go语言中不允许将整型强制转换为布尔型.一个简单的例子:var b bool = true。
字符串的值为双引号中的内容,可以在Go语言的源码中直接添加非ASCII码字符,代码如下:
str := “hello world”
ch := “中文”
切片是一个拥有相同类型元素的可变长度序列,切片的声明方式如下:
var name []T
其中T代表切片元素类型,可以是整型,浮点型,布尔型,切片,map,函数等.
切片的元素使用"[]"进行访问,在方括号中提供切片的索引即可访问元素,索引的范围从0开始,切不超过切片的最大容量,代码如下:
a := make([]int, 3)//创建一个容量为3的整型切片
a[0] = 1//为切片元素赋值
a[1] = 2
a[2] = 3
字符串也可以按切片的方式进行操作:
str := "hello world"
fmt.Println(str[6:])
代码输出如下:
world
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
声明变量的一般形式是使用 var 关键字:
var identifier type
可以一次声明多个变量:
var identifier1, identifier2 type
package main
import "fmt"
func main() {
var a string = "Runoob"
fmt.Println(a)
var b, c int = 1, 2
fmt.Println(b, c)
}
输出结果
Runoob
1 2
未初始化默认值
注意
省略 var, 注意 := 左侧如果没有声明新的变量,就产生编译错误,例如
var intVal int
intVal :=1 // 这时候会产生编译错误
intVal,intVal1 := 1,2 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句
可以将 var f string = “Runoob” 简写为 f := “Runoob”
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。
a 和 b 的类型(int 和 bool)将由编译器自动推断。
这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。
我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上 var 关键字其实是显得有些多余了,因此我们可以将它们简写为 a := 50 或 b := false。
a 和 b 的类型(int 和 bool)将由编译器自动推断。
这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。使用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。
如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a,两个变量的类型必须是相同。
空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。
_ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量的定义格式:
const identifier type = value
你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
显式类型定义: const b string = “abc”
隐式类型定义: const b = “abc”
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
iota 可以被用作枚举值:
第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:
const (
a = iota
b
c
)
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
以上实例运行结果为:
0 1 2 ha ha 100 100 7 8
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
嵌套语句
if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
和 C 语言的 for 一样:
for init; condition; post { }
和 C 的 while 一样:
for condition { }
和 C 的 for(;
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!