优势:
- 极简单的部署方式:可直接编译成机器码,不依赖其他库,直接运行即可部署
- 静态类型语言:
- 编译的时候检查出来隐藏的大多数问题
- 语言层面的并发:
- 天生支持
- 充分利用多核
- 标准库:
- runtime系统调度机制
- 高效的GC垃圾回收
- 丰富的标准库
- 简单易学
- 25个关键字
- C语言简洁基因
- 跨平台
- 面向对象
缺点:
- 无泛化类型
- 包管理大部分都在github上
- 所有Exception都用error来处理
- 对C的降级处理不是无缝的,不像C->asm那么完美(序列化问题)
Hello world
package main
import (
"fmt"
)
func main(){
var a int = 1
fmt.Println("hello go!")
}
变量,常量
变量 var
有var就是=
没有就是:=
方法1:声明一个变量,默认值是0
var a int
//默认a=0
方法2:声明一个变量并初始化
var b int = 10
方法3:初始化时省略数据类型,自动匹配
var c = 10
//自动推导
方法4:直接自动匹配//不支持全局变量
d:= 10
多个变量声明
单行写法
var aa,bb int =100,200
var cc,dd = 100, "miao"
多行写法
var(
vv int = 100
gg bool = true
)
常量,枚举,const与iota
const 关键字可以用于定义常量
const a int = 10
const还可以定义枚举类型,iota用在const中作为一个每行+1的量 第一行iota=0 公式不变
const (
SHANGHAI = 1
SHENZHEN = 2
BEIJING = 3
)
与以下是一样的
const (
SHANGHAI = iota
SHENZHEN
BEIJING
)
//=================================
const (
SHANGHAI = 10*iota
SHENZHEN
BEIJING
)
相当于
const (
SHANGHAI = 0
SHENZHEN = 10
BEIJING = 20
)
//================================
const (
a,b = iota + 1, iota +2 //1,2
c,d //2,3
e,f = iota*2, iota*3 //6,9
c,d //8,12
)
函数,多返回值
多返回值
func foo1(a string, b int) {
blabla
}
func foo2(a string, b int) int {
blabla
c:=10
return c
}
func foo3(a string, b int) (int,int) {
blabla
c,d:=10,20
return c,d
}
func foo4(a string ,b int)(r1 int,r2 int){
r1:=10
r2:=20 //不赋值则默认0
//作用域是函数体整个空间内
return
}
通常把对外开放的函数大写开头,私有函数小写开头
init函数与import导包
先层层import,init()执行后再返回
引入路径填相对于gopath的路径
可以给包起别名
import(
_ "xxxx/xxxx" //匿名导入 可以不使用包内方法,但是init
mylib "yyyy" //mylib.AAA() 可以使用包的方法
"qqqqq/cccc"
. "qqqqqqqqqq" //导入包中的全部方法 可以直接调用不需要加包名
)
指针,引用
p 根据地址找内存
&a 取地址
p := &a p是int类型的
可以多多多级指针
defer
defer后面的表达式在结束之前执行,类似于析构函数,是一种压栈的形式
return先执行,defer后执行
func A(){
}
func B(){
}
func C(){
}
func E(){
}
func main(){
defer A()
defer B()
defer C()
defer fmt.Println("D")
return E()
}
E
D
C
B
A
数组,切片slice
var myArray1 [10]int //普通数组
var myArray2 [4]int{1,2,3,4} //普通数组
for i:=0 ;i< len(myArray1);i++ {
fmt.Println(myArray1[i])
}
for index,value := range myArray2{
fmt.Println("index=",index,"value=",value)
}
数组在函数中传递时候传递的是一个拷贝的值,且根据不同的长度有不同的类型
myArray1 的类型是[10]int, myArray2的类型是[4]int,在函数传递的时候会类型不匹配
func A(arr [4]int) {
arr[0]=10 //无法改变实际上的arr[0]
}
切片数组
myArray:=[]int{1,2,3,4}
func A(arr []int) {//引用传递
arr[0]=10 //可以改变实际上的arr[0],传的是一个指针
}
slice四种声明方式
var a =make([]int,15)
slice1 := []int{1,2,3}
var slice2 []int
slice2 = make([]int,3)
var slice3 []int =make([]int,3)
slice4 := make([]int,3)
判断slice是否为空
if slice1 == nil {
blabla 空切片
}else{
blabla 分配过的切片
}
slice切片与追加
var a =make([]int,3,5) //长度3容量5
a=append(a,1) //长度4容量5
a=append(a,2) //长度5容量5
a=append(a,3) //长度6容量10 超出容量的时候容量会x2
var b =make([]int,3) //长度3容量3 如果扩容就变成6
扩容机制:超出容量的时候容量会x2
截取
s := []int{1,2,3}
s1 := s[0:1] //前闭后开,和python一样 默认上限len(s),默认下限0 [1:], [:2]都是可以的
这里指向的底层地址一致,改s1[0]也会改变s[0]
可以用copy得到深拷贝
s2:= mask([]int,3)
copy(s2,s) //s中的值拷贝至s2
map
三种声明方式
//方法1
声明 MyMap1是一种map类型,key是string,value是int
var myMap1 map[string]int
目前myMap1==nil
myMap1=make(map[string]int,10) 使用map前需要先用make给map分配数据空间 一样能够自动扩容
myMap1["one"]=10
myMap2["two"]=20
必须make否则会报错
//方法2
myMap2 := make(map[string]int)
myMap2["one"]=10
myMap2["two"]=20
//方法3
myMap3 := map[string]string{
"one":10,
"two":20,
}
//===========================
使用
//===========================
//添加 略
//遍历
for key,value := range myMap3{
fmt.Println(key,value)
}
//删除
delete(myMap3,"one")
//修改和添加一样
//传参的时候传的是指针
func changeMap(mapa map[string]int){ //引用传递
mapa["one"]=1
}
//完全拷贝需要再定义一个map把值复制过去
struct类与对象
type myint int
//声明一个int的别名叫myint
//定义一个结构体
type Book struct{
title string
auth string
}
func changeBook1(book Book){ //值传递
book.auth = "444" //不会变
}
func changeBook2(book *Book){
book.auth = "111" //会变
}
func main(){
var book1 Book
book1.title = "golang"
book1.auth = "zhang3"
fmt.Printf("%v\n",book1)//会逐个输出Book中的变量值
//输出的会是 {golang zhang3}
changeBook1(book)
fmt.Printf("%v\n",book1)
//输出的会是 {golang zhang3}
changeBook2(&book1)
fmt.Printf("%v\n",book1)
//输出的会是 {golang 111}
}
类
//如果类名首字母大写表示其他包也能够定义这个对象
type Hero struct{
Name string //如果说类的属性首字母大写表示该属性共有,否则的话只能够类的内部访问
Ad int
level int //私有属性
}
func (this *Hero) Show(){ //方法首字母大写表示在其他包中能够调用 小写表示其他包不能调用
fmt.Println("",........)
}
func (this Hero) SetName(a strnig){ //这里传递的是this的一个拷贝
this.Name=a
}
func (this *Hero) SetName(a string){
this.Name=a
}
- 注意this* 否则只能访问一个副本
- 注意首字母大小写有区别,大写表示对外访问,小写只能在本包内访问
继承
type Human struct{
name string
sex string
}
func (this *Human) Eat(){
fmt.Println("Human.Eat()")
}
func (this *Human) Walk(){
fmt.Println("Human.Walk()")
}
typedef Superman struct{
Human //Superman类继承了Human类的方法
level int
}
//重定义父类方法
func (this* Superman) Eat(){
fmt.Println("Superman.Eat()")
}
//子类新方法
func (this* Superman) Fly(){
fmt.Println("Superman.Eat()")
}
func main(){
h:=Human{"zhang3","female"}
h.Eat()
h.Walk()
s:=Superman{Human{"li4","male"},88}
//或者
var s Superman
s.name = "li4"
s.sex = "male"
s.level = 88
s.Walk() //human walk
s.Eat() //superman eat
s.Fly() //superman fly
}
多态 interface
基本要素
- 有一个父类
- 有子类,实现了父类的全部接口方法
- 父类类型的变量(指针) 指向(引用) 子类的具体数据变量
```go
type AnimalIF interface{ //是一个指针!!!!!!!!!!!!!!!!
Sleep()
GetColor() string //获取动物的颜色 GetType() string //获取动物的种类 }
//不需要把AnimalIF显式写下来,重写该接口的[所有]方法,就可以用一个AnimalIF指针指向Cat type Cat struct{ color string }
func (this* Cat) GetColor(){ return this.color }
func (this* Cat) GetType(){ return “Cat” }
func (this* Cat) Sleep(){ fmt.Println(“Cat sleeping”) }
type Dog struct{ color string }
func (this* Dog) GetColor(){ return this.color }
func (this* Dog) GetType(){ return “Dog” }
func (this* Dog) Sleep(){ fmt.Println(“Dog sleeping”) }
func showAnimal (animal AnimalIF){ animal.Sleep() //多态 fmt.Println(“color = “,animal.GetColor()) }
func main(){
var animal AnimalIF //接口数据类型
animal = &Cat{"Green"}
animal.Sleep()
animal = &Dog("Yellow")
animal.Sleep()
showAnimal(animal)
<a name="gs0sb"></a>
## 空接口 interface{} 通用万能类型,类型断言
int、string、float32、float64、struct 都实现了 interface
```go
func myFunc(arf interface{}){
fmt.Println("myFunc called")
fmt.Println(arg)
//interface{}实际类型区分办法:断言
value,ok := arg.(string)
if ok{
是string类型
}else{
不是string类型
fmt.Printf("value type is %T\n", value)
}
}
type Book struct{
auth string
}
func main(){
bool:= Book{"Golang"}
myFunc(book)
myFunc(100)
}
反射
变量的结构
反射 通过一个变量得到type、值
var a string
//pair<statictype:string, value:"aceld">
a="aceld"
//pair<type:string,value:"aceld">
var allType interface{}
allType = a
str,_:=allType.(string)
fmt.Println(str) //aceld
断言可以用于强制转换
pair是不会变的.
reflect包:ValueOf,TypeOf
动态获取未知数据类型和值
package main
import(
"fmt"
"reflect"
)
func reflectNum(arg interface{}){
fmt.Println("type:", reflect.TypeOf(arg)," value:",reflect.ValueOf(arg))
}
type User struct{
Id int
Name string
Age int
}
func (this* User) Call(){
fmt.Println("User id called ..")
fmt.Printf("%v\n", this)
}
func man(){
var num float64 = 1.2345
user:= User{1,"Aceld",18}
}
func DoFIleAndMethod(input interface{}){
//获取type
inputType:= reflect.TypeOf(input)
fmt.Prinln("type is ",inputType.Name())
//获取value
inputValue:= reflect.ValueOf(input)
fmt.Prinln("value is ",inputValue)
//通过type获取里面的字段
for i :=0; i< inputType.NumField(); i++{
field := inputType.Field(i)
value := inputValue.Field(i).Interface()
fmt.Printf("%s:%v = %v\n",field.Name,field.Type,value)
}
//通过type获取里面的方法,调用
for i := 0; i< inputType.NumMethod();i++{
m:=inputType.Method(i)
fmt.Printf("%s:%v\n",m.Name,m.Type)
}
}
详细接口看文档
结构体标签
type resume struct{
Name string `info:"name" doc:"我的名字"`
Sex string `info:"sex"`
}
func findTag(str interface{}){
t:=reflect.TYpeOf(str).Elem()
for i:=0; i<t.NumField();i++{
taginfo :=t.Field(i).Tag.Get("info")
tagdoc := t.Field(i).Tag.Get("doc")
}
}
func main(){
var re resume
findTag(&re)
}
结构体标签在json中的使用
可以应用在json编解码,orm映射关系等