专一于大数据及容器云核心技术解密,可提供全栈的大数据+云原平生台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,若有任何学术交流,可随时联系。详情请关注《数据云技术社区》公众号。 java
hello.go
package main
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Hello())
}
# 安装GO 1.11及以上版本
go version
# 开启module功能
export GO111MODULE=on
# 进入到项目目录
cd /home/gopath/src/hello
# 初始化
go mod init
# 编译
go build
#加载依赖包,自动归档到vendor目录
go mod vendor -v
# 文件目录结构
./
├── go.mod
├── go.sum
├── hello # 二进制文件
├── hello.go
└── vendor
├── golang.org
├── modules.txt
└── rsc.io
复制代码
go get -u github.com/golang/dep/cmd/dep
#进入到项目目录
cd /home/gopath/src/demo
#dep初始化,初始化配置文件Gopkg.toml
dep init
#dep加载依赖包,自动归档到vendor目录
dep ensure
# 最终会生成vendor目录,Gopkg.toml和Gopkg.lock的文件
复制代码
一、单变量声明,类型放在变量名以后,能够为任意类型
var 变量名 类型
二、多变量同类型声明
var v1,v2,v3 string
三、多变量声明
var {
v1 int
v2 []int
}
四、使用关键字var,声明变量类型并赋值
var v1 int=10
五、使用关键字var,直接对变量赋值,go能够自动推导出变量类型
var v2=10
六、直接使用“:=”对变量赋值,不使用var,二者同时使用会语法冲突,推荐使用
v3:=10
七、能够限定常量类型,但非必需
const Pi float64 = 3.14
八、无类型常量和字面常量同样
const zero=0.0
九、多常量赋值
const(
size int64=1024
eof=-1
)
十、常量的多重赋值,相似变量的多重赋值
const u,v float32=0,3
const a,b,c=3,4,"foo" //无类型常量的多重赋值
十一、常量赋值是编译期行为,能够赋值为一个编译期运算的常量表达式
const mask=1<<3
复制代码
//布尔类型的关键字为bool,值为true或false,不可写为0或1
var v1 bool
v1=true
//接受表达式判断赋值,不支持自动或强制类型转换
v2:=(1==2)
//int和int32为不一样类型,不会自动类型转换须要强制类型转换
//强制类型转换需注意精度损失(浮点数→整数),值溢出(大范围→小范围)
var v2 int32
v1:=64
v2=int32(v1)
//浮点型分为float32(相似C中的float),float64(相似C中的double)
var f1 float32
f1=12 //不加小数点,被推导为整型
f2:=12.0 //加小数点,被推导为float64
f1=float32(f2) //须要执行强制转换
//复数的表示
var v1 complex64
v1=3.2+12i
//v1 v2 v3 表示为同一个数
v2:=3.2+12i
v3:=complex(3.2,12)
//实部与虚部
//z=complex(x,y),经过内置函数实部x=real(z),虚部y=imag(z)
//声明与赋值
var str string
str="hello world"
//建立数组
var array1 [5]int //声明:var 变量名 类型
var array2 [5]int=[5]int{1,2,3,4,5} //初始化
array3:=[5]int{1,2,3,4,5} //直接用“:=”赋值
[3][5]int //二维数组
[3]*float //指针数组
//数组元素访问
for i,v:=range array{
//第一个返回值为数组下标,第二个为元素的值
}
//建立切片,基于数组建立
var myArray [5]int=[5]{1,2,3,4,5}
var mySlice []int=myArray[first:last]
slice1=myArray[:] //基于数组全部元素建立
slice2=myArray[:3] //基于前三个元素建立
slice3=myArray[3:] //基于第3个元素开始后的全部元素建立
//直接建立
slice1:=make([]int,5) //元素初始值为0,初始个数为5
slice2:=make([]int,5,10) //元素初始值为0,初始个数为5,预留个数为10
slice3:=[]int{1,2,3,4,5} //初始化赋值
//基于切片建立
oldSlice:=[]int{1,2,3,4,5}
newSlice:=oldSlice[:3] //基于切片建立,不能超过原切片的存储空间(cap函数的值)
//动态增减元素,切片分存储空间(cap)和元素个数(len),当存储空间小于实际的元素个数,会从新分配一块原空间2倍的内存块,并将原数据复制到该内存块中,合理的分配存储空间能够以空间换时间,下降系统开销。
//添加元素
newSlice:=append(oldSlice,1,2,3) //直接将元素加进去,若存储空间不够会按上述方式扩容。
newSlice1:=append(oldSlice1,oldSlice2...) //将oldSlice2的元素打散后加到oldSlice1中,三个点不可省略。
//内容复制,copy()函数能够复制切片,若是切片大小不同,按较小的切片元素个数进行复制
slice1:=[]int{1,2,3,4,5}
slice2:=[]int{6,7,8}
copy(slice2,slice1) //只会复制slice1的前三个元素到slice2中
copy(slice1,slice1) //只会复制slice2的三个元素到slice1中的前三个位置
//map先声明后建立再赋值
var map1 map[键类型] 值类型
//建立
map1=make(map[键类型] 值类型)
map1=make(map[键类型] 值类型 存储空间)
//赋值
map1[key]=value
// 直接建立
m2 := make(map[string]string)
// 而后赋值
m2["a"] = "aa"
m2["b"] = "bb"
// 初始化 + 赋值一体化
m3 := map[string]string{
"a": "aa",
"b": "bb",
}
//delete()函数删除对应key的键值对,若是key不存在,不会报错;若是value为nil,则会抛出异常(panic)。
delete(map1,key)
//元素查找
value,ok:=myMap[key]
if ok{
//若是找到
//处理找到的value值
}
//遍历
for key,value:=range myMap{
//处理key或value
}
复制代码
//在if以后条件语句以前能够添加变量初始化语句,用;号隔离
if <条件语句> { //条件语句不须要用括号括起来,花括号必须存在
//语句体
}else{
//语句体
}
//在有返回值的函数中,不容许将最后的return语句放在if...else...的结构中,不然会编译失败
//例如如下为错误范例
func example(x int) int{
if x==0{
return 5
}else{
return x //最后的return语句放在if-else结构中,因此编译失败
}
}
复制代码
//一、根据条件不一样,对应不一样的执行体
switch i{
case 0:
fmt.Printf("0")
case 1: //知足条件就会退出,只有添加fallthrough才会继续执行下一个case语句
fmt.Prinntf("1")
case 2,3,1: //单个case能够出现多个选项
fmt.Printf("2,3,1")
default: //当都不知足以上条件时,执行default语句
fmt.Printf("Default")
}
//二、该模式等价于多个if-else的功能
switch {
case <条件表达式1>:
语句体1
case <条件表达式2>:
语句体2
}
复制代码
//一、Go只支持for关键字,不支持while,do-while结构
for i,j:=0,1;i<10;i++{ //支持多个赋值
//语句体
}
//二、无限循环
sum:=1
for{ //不接条件表达式表示无限循环
sum++
if sum > 100{
break //知足条件跳出循环
}
}
//三、支持continue和break,break能够指定中断哪一个循环,break JLoop(标签)
for j:=0;j<5;j++{
for i:=0;i<10;i++{
if i>5{
break JLoop //终止JLoop标签处的外层循环
}
fmt.Println(i)
}
JLoop: //标签处
...
复制代码
//关键字goto支持跳转
func myfunc(){
i:=0
HERE: //定义标签处
fmt.Println(i)
i++
if i<10{
goto HERE //跳转到标签处
}
}
复制代码
//一、函数组成:关键字func ,函数名,参数列表,返回值,函数体,返回语句
//先名称后类型
func 函数名(参数列表)(返回值列表){ //参数列表和返回值列表以变量声明的形式,若是单返回值能够直接加类型
函数体
return //返回语句
}
//例子
func Add(a,b int)(ret int,err error){
//函数体
return //return语句
}
//二、函数调用
//先导入函数所在的包,直接调用函数
import "mymath"
sum,err:=mymath.Add(1,2) //多返回值和错误处理机制
复制代码
//多返回值
func (file *File) Read(b []byte) (n int,err error)
//使用下划线"_"来丢弃返回值
n,_:=f.Read(buf)
复制代码
//匿名函数:不带函数名的函数,能够像变量同样被传递。
func(a,b int,z float32) bool{ //没有函数名
return a*b<int(z)
}
f:=func(x,y int) int{
return x+y
}
复制代码
type Rect struct{ //定义矩形类
x,y float64 //类型只包含属性,并无方法
width,height float64
}
func (r *Rect) Area() float64{ //为Rect类型绑定Area的方法,*Rect为指针引用能够修改传入参数的值
return r.width*r.height //方法归属于类型,不归属于具体的对象,声明该类型的对象便可调用该类型的方法
}
复制代码
type Integer int
func (a Integer) Less(b Integer) bool{ //表示a这个对象定义了Less这个方法,a能够为任意类型
return a<b
}
//类型基于值传递,若是要修改值须要传递指针
func (a *Integer) Add(b Integer){
*a+=b //经过指针传递来改变值
}
复制代码
new()
func new(Type) *Type
内置函数 new 分配空间。传递给new 函数的是一个类型,不是一个值。返回值是指向这个新分配的零值的指针
//建立实例
rect1:=new(Rect) //new一个对象
rect2:=&Rect{} //为赋值默认值,bool默认值为false,int默认为零值0,string默认为空字符串
rect3:=&Rect{0,0,100,200} //取地址并赋值,按声明的变量顺序依次赋值
rect4:=&Rect{width:100,height:200} //按变量名赋值不按顺序赋值
//构造函数:没有构造参数的概念,一般由全局的建立函数NewXXX来实现构造函数的功能
func NewRect(x,y,width,height float64) *Rect{
return &Rect{x,y,width,height} //利用指针来改变传入参数的值达到相似构造参数的效果
}
//方法的重载,Go不支持方法的重载(函数同名,参数不一样)
//v …interface{}表示参数不定的意思,其中v是slice类型,及声明不定参数,能够传入任意参数,实现相似方法的重载
func (poem *Poem) recite(v ...interface{}) {
fmt.Println(v)
}
复制代码
func (base *Base) Foo(){...} //Base的Foo()方法
func (base *Base) Bar(){...} //Base的Bar()方法
type Foo struct{
Base //经过组合的方式声明了基类,即继承了基类
...
}
func (foo *Foo) Bar(){
foo.Base.Bar() //并改写了基类的方法,该方法实现时先调用基类的Bar()方法
... //若是没有改写即为继承,调用foo.Foo()和调用foo.Base.Foo()的做用的同样的
}
//修改内存布局
type Foo struct{
... //其余成员信息
Base
}
//以指针方式组合
type Foo struct{
*Base //以指针方式派生,建立Foo实例时,须要外部提供一个Base类实例的指针
...
}
//名字冲突问题,组合内外若是出现名字重复问题,只会访问到最外层,内层会被隐藏,不会报错,即相似java中方法覆盖/重写。
type X struct{
Name string
}
type Y struct{
X //Y.X.Name会被隐藏,内层会被隐藏
Name string //只会访问到Y.Name,只会调用外层属性
}
复制代码
type Rect struct{
X,Y float64
Width,Height float64 //字母大写开头表示该属性能够由包外访问到
}
func (r *Rect) area() float64{ //字母小写开头表示该方法只能包内调用
return r.Width*r.Height
}
复制代码
type File struct{
//类的属性
}
//File类的方法
func (f *File) Read(buf []byte) (n int,err error)
func (f *File) Write(buf []byte) (n int,err error)
func (f *File) Seek(off int64,whence int) (pos int64,err error)
func (f *File) Close() error
//接口1:IFile
type IFile interface{
Read(buf []byte) (n int,err error)
Write(buf []byte) (n int,err error)
Seek(off int64,whence int) (pos int64,err error)
Close() error
}
//接口2:IReader
type IReader interface{
Read(buf []byte) (n int,err error)
}
//接口赋值,File类实现了IFile和IReader接口,即接口所包含的全部方法
var file1 IFile = new(File)
var file2 IReader = new(File)
复制代码
//接口animal
type Animal interface {
Speak() string
}
//Dog类实现animal接口
type Dog struct {
}
func (d Dog) Speak() string {
return "Woof!"
}
//Cat类实现animal接口
type Cat struct {
}
func (c Cat) Speak() string {
return "Meow!"
}
//Llama实现animal接口
type Llama struct {
}
func (l Llama) Speak() string {
return "?????"
}
//JavaProgrammer实现animal接口
type JavaProgrammer struct {
}
func (j JavaProgrammer) Speak() string {
return "Design patterns!"
}
//主函数
func main() {
animals := []Animal{Dog{}, Cat{}, Llama{}, JavaProgrammer{}} //利用接口实现多态
for _, animal := range animals {
fmt.Println(animal.Speak()) //打印不一样实现该接口的类的方法返回值
}
}
复制代码
//定义调用体
func Add(x,y int){
z:=x+y
fmt.Println(z)
}
//go关键字执行调用,即会产生一个goroutine并发执行
//当函数返回时,goroutine自动结束,若是有返回值,返回值会自动被丢弃
go Add(1,1)
//并发执行
func main(){
for i:=0;i<10;i++{//主函数启动了10个goroutine,而后返回,程序退出,并不会等待其余goroutine结束
go Add(i,i) //因此须要经过channel通讯来保证其余goroutine能够顺利执行
}
}
复制代码
//一、channel声明,声明一个管道chanName,该管道能够传递的类型是ElementType
//管道是一种复合类型,[chan ElementType],表示能够传递ElementType类型的管道[相似定语从句的修饰方法]
var chanName chan ElementType
var ch chan int //声明一个能够传递int类型的管道
var m map[string] chan bool //声明一个map,值的类型为能够传递bool类型的管道
复制代码
//缓冲机制
c:=make(chan int,1024) //第二个参数为缓冲区大小,与切片的空间大小相似
//经过range关键字来实现依次读取管道的数据,与数组或切片的range使用方法相似
for i :=range c{
fmt.Println("Received:",i)
}
//超时机制:利用select只要一个case知足,程序就继续执行而不考虑其余case的状况的特性实现超时机制
timeout:=make(chan bool,1) //设置一个超时管道
go func(){
time.Sleep(1e9) //设置超时时间,等待一分钟
timeout<-true //一分钟后往管道放一个true的值
}()
//
select {
case <-ch: //若是读到数据,则会结束select过程
//从ch中读取数据
case <-timeout: //若是前面的case没有调用到,一定会读到true值,结束select,避免永久等待
//一直没有从ch中读取到数据,但从timeout中读取到了数据
}
复制代码
//管道写入,把值想象成一个球,"<-"的方向,表示球的流向,ch即为管道
//写入时,当管道已满(管道有缓冲长度)则会致使程序堵塞,直到有goroutine从中读取出值
ch <- value
//管道读取,"<-"表示从管道把球倒出来赋值给一个变量
//当管道为空,读取数据会致使程序阻塞,直到有goroutine写入值
value:= <-ch
复制代码
//每一个case必须是一个IO操做,面向channel的操做,只执行其中的一个case操做,一旦知足则结束select过程
//面向channel的操做无非三种状况:成功读出;成功写入;即没有读出也没有写入
select{
case <-chan1:
//若是chan1读到数据,则进行该case处理语句
case chan2<-1:
//若是成功向chan2写入数据,则进入该case处理语句
default:
//若是上面都没有成功,则进入default处理流程
}
复制代码
P能够偷任务(即goroutine),当某个P的本地G执行完,且全局没有G须要执行的时候,P能够去偷别的P尚未执行完的一半的G来给M执行,提升了G的执行效率。git
专一于大数据及容器云核心技术解密,可提供全栈的大数据+云原平生台咨询方案,请持续关注本套博客。QQ邮箱地址:1120746959@qq.com,若有任何学术交流,可随时联系。详情请关注《数据云技术社区》公众号。github