Golang简介
环境安装
源码下载
http://golang.org/dl
安装
直接解压后放在 /usr/local/
编译器是 /usr/local/go/bin/go
源码在 /usr/local/go/src
配置环境变量
编辑 .bashrc
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
运行go version 检查安装是否成功
GOPATH 代表开发代码的默认路径, 后面有其他管理工具
IDE
- VS Code
- Goland (收费)
Golang的优势
- 直接编译成机器码,性能好,类C级性能
- 不依赖其它库,内连接
- 直接运行不需部署
- 静态语言
- 底层支持并发, 操作简单性能高
- runtime系统调用机制
- 高效垃圾回收
- 丰富的标准库
- 内嵌C语言
- 跨平台
Golang适用产品
云原生
docker, k8s, etcd, consul, cloudflare
数据库
tidb, influxdb, cockroachdb
微服务
go-kit, micro, typhon
区块链
以太坊, hyperledger
Golang的不足
- 包管理不够完善
- 没有泛型(Generlization)
- 没有Try Catch, 只有Error
Golang 特色语法
Hello World
src就是workspace, 里面的每一个文件夹就是一个工程
mkdir firstGolang
package main // main function
import (
"fmt"
"time"
)
//main function
func main(){
fmt.Println("Hello Go!")
time.Sleep(1 * time.Second)
fmt.Println("Hello Go!")
}
Golang定义变量
//推算类型, 冒等, 不能用来定义全局变量
name := "alvin"
//显式指定
var name string = "alvin"
//var定义推断类型
var name = "alvin"
//默认值a=0
var a int
//常量累加赋值, iota每次换行就会加一
//iota只能在const()内使用, 类似Excel
const(
BEIJING = iota //1
SHANGHAI //2
SHENHEN //3
)
多返回值
//返回值必须有实际类型
//带名称返回值在复制前已经有默认值
func foo3(a string, b int) (r1, r2 int) {
//命名返回值不用在return里显式给出
return // 0, 0
}
func foo4(a string, b int) (int, int) {
//匿名返回值就是正常用法
return 1, 2;
}
func main() {
c, d := foo3("a", 10)
fmt.Println("c = ", c, "d = ", d)
e, f := foo4("a", 10)
fmt.Println("e = ", c, "f = ", d)
}
导入包
package main
import "lib1"
//别名导入, 用别名使用
import mylib "lib3"
//匿名导入, 不使用不会报错, 进调用包的init()方法
import _ "lib2"
//静态导入方法, 容易造成命名空间冲突
import . "lib4"
func main() {
lib1.Lib1Func()
mylib.Test()
//直接使用lib4方法
Lib4Func()
}
//构造函数
func init() {
}
---
package lib1
func Lib1Func(){
}
包搜索路径 $GOPATH
函数名首字母大写代表公有函数, 首字母小写代表私有函数
导入包必须使用
指针 (不常用)
就是直接传实参的内存引用, 接收函数通过指针对参数的修改在函数外部也生效
//接旨
func changeVal(p *int){
//修改内存
*p = 10;
}
func main() {
var a int = 1;
//传旨
changeVal(&a)
fmt.Println("a=",a)
}
//二级指针, 指向指针的指针
ver pp **int
defer(finalizer)
defer类似类的finalizer和try里面的finally函数, 在声明代码体的最后执行
defer在return之后执行, 这一点是和Java不同的
多条defer后添加的先执行
func main() {
//finalizer
defer fmt.Println("Main end 1")
defer fmt.Println("Main end 2") //后入先出, end 2 先执行
fmt.Println("main::1")
fmt.Println("main::2")
testReturn(); //输出 return called, defer called. 因为defer在函数花括号结束处运行
}
func testReturn() int {
defer fmt.Println("defer called")
return returnFunc();
//defer在这里运行
}
func returnFunc() int {
fmt.Println("return called");
return 0;
}
数组
数组的定义
定长数组
缺点
- 作为方法入参也需要指定数组长度, 非常不灵活
- 作为方法入参是值传递
//定长数组
var myArray [10]int
//初始化值
var myArray2 [10]int{1,2,3,4}
for i := 0; i<10; i++ {
fmt.Println(myArray[i])
}
for index, value := range myArray2 {
fmt.Println("index = ", index, ", value = ", value)
}
//定长数组的长度是类型的一部分
//如果要使用定长数组入参要带数组长度
func func10(array [10]int){
}
动态数组(切片)
长度不限
引用传递, 函数内直接修改
var myArray1 = []int{}
var myArray2 = []int{1,2,3,4}
数组遍历
//for循环遍历
for i:=0;i<len(myArray);i++ {
fmt.Println(myArray[i])
}
//range遍历(foreach)
for index, value := range myArray {
fmt.Println("index = ", index, "value = ", value)
}
//range遍历放弃index, 声明为匿名变量
for _, value := range myArray {
fmt.Println("value = ", value)
}
切片
声明方式
切片的长度len表示切片可用长度
切片的容量cap表示内存中保留的总空间
slace1 := []int
var slace2 []int
slace2 = make([]int, 3)
//常用方式
slace3 := make([]int, 3)
//声明额外空间
slace4 := make([]int, 3, 5)
//切片的长度和总空间, 3, 5
fmt.Printf("lens = ", len(slace4), "cap = ", cap(slace4))
切片追加元素
//会使用总空间内额外的部分. 如果总空间不够了, 会创建一个2 * len的空间
slace4 = append(slace4, 1);
截取切片
切片截取的是引用, 修改会影响原始数据
slace1 := []int{1,2,3}
slace2 = slace1[:2] //0~2
深copy
slace3 := make([]int, 3)
//slace1复制到slace3
copy(slace3, slace1)
Map
声明Map
//key和value都是string
//var myMap map[string]string
//第一种方式 创建10个存储空间
myMap1 := make(map[string]string, 10)
myMap1["one"] = "java"
myMap1["two"] = "c++"
fmt.Println(myMap1)
//第二种方式 创建map使用默认存储空间, 不够会自动追加
myMap2 := make(map[string]string)
myMap2["one"] = "java"
myMap2["two"] = "c++"
fmt.Println(myMap2)
//第三种方式 创建同时赋值
myMap3 := map[string]string{
"one": "java",
"two": "c++",
}
fmt.Println(myMap3)
遍历Map
cityMap := make(map[string]string)
//添加
cityMap["China"] = "Beijing"
cityMap["Japan"] = "Tokyo"
//遍历
for key, value := range cityMap {
fmt.Println("key=", key, " value=", value)
}
//删除
delete(cityMap, "China")
//修改
cityMap["Japan"] = "Shanghai"
Struct结构体
结构体对象是值传递的, 如果想在函数内修改结构体对象的值, 需要使用指针赋值
//首字母大写才能被其它包访问
type Book struct {
title string
auth string
}
//把this绑定为当前Book对象的指针. 等于这个方法就是操作Book对象内数据的
//其实就是为Book结构体定义了一个方法
func (this *Book) GetName() string {
return this.title
}
func (this *Book) SetName(newName string){
this.title = newName
}
func main() {
var book1 Book
book1.title = "Golang"
book1.auth = "Alvin"
fmt.Println(book1)
fmt.Println(book1.GetName());
book1.SetName("Python")
fmt.Println(book1.GetName());
}
继承
type Human struct {
name string
sex string
}
func (this *Human) Eat() {
fmt.Println("Human Eat")
}
func (this *Human) Walk() {
fmt.Println("Human Walk")
}
type SuperMan struct {
Human //继承了Human
skill string
}
func (this *SuperMan) Eat() {
fmt.Println("SuperMan Eat")
}
func (this *SuperMan) Fight() {
fmt.Println("SuperMan Fight by", this.skill)
}
func main() {
//对象初始化赋值
// hu0 := Human{}
// var hu00 Human
hu := Human{sex:"female", name:"zhang"}
su := SuperMan{Human{"liu", "male"}, "Laser"}
hu.Eat()
su.Eat()
su.skill = "Laser"
su.Fight()
}
Interface
接口本身是一个指针, 接收对象实例时只能传入指针&
type AnimalIF interface {
Sleep()
GetColor() string
GetType() string
}
type Cat struct {
color string
}
//不用this也要定义, 否则方法不能绑定到类上
func (this *Cat) Sleep(){
fmt.Println("Cat sleep")
}
func (this *Cat) GetColor() string {
return this.color;
}
func (this *Cat) GetType() string {
return "Cat";
}
//Dog实现省略
func main() {
var animal AnimalIF
//必须用指针
animal = &Cat{"white"}
showAnimal(animal)
}
//传入指针完成多态
func showAnimal(animal AnimalIF) {
fmt.Println(animal.GetColor())
animal.Sleep()
}
元类/类型判断 interface{} (Object类, 万能接口, instanceof)
//元类型 Object
func acceptAny(arg interface{}){
fmt.Println(arg)
}
func acceptInt(arg interface{}) {
//类型判断 instanceof
value, ok := arg.(int)
if ok {
fmt.Println(value) //Same as arg
}
}
func main() {
acceptAny(123)
acceptAny("abc")
acceptInt(123)
acceptInt("abc")
}
变量的内部结构
变量
- type
- static type (基本类型 int, string)
- concrete type (接口类型, 自定义类)
- value
func main() {
var a string
//pari<type:string, value:"abc">
a = "abc"
var allType interface{}
allType = a
//读取实例pair里保存的type和value
value, ok := a.(string)
}
类型转换
//接口1
type Writer interface {
Write()
}
//接口2
type Reader interface {
Read()
}
//实现类
type Book struct {
name string;
}
//实现接口1
func (this *Book) Write() {
fmt.Println("Write book")
}
//实现接口2
func (this *Book) Read() {
fmt.Println("Read book")
}
func main() {
//创建实例, 保存指针
book := &Book{}
//把指针赋值给接口1
var w Writer = book
//调用接口1方法
w.Write()
//强转成接口2, (需要实现接口2)
var r Reader = w.(Reader)
//调用接口2方法
r.Read()
}
反射
import (
"fmt"
"reflect"
)
func main() {
var num float64 = 1.234
reflectNum(num)
}
//接收任意类型
func reflectNum(arg interface{}) {
//读取类型
fmt.Println("type: ", reflect.TypeOf(arg))
//读取值
fmt.Println("value: ", reflect.ValueOf(arg))
//type: float64
//value: 1.234
}
type User struct {
Id int
Name string
Age int
}
func (this *User) Call() {
fmt.Println("User is :", this)
}
func main() {
user := User{1, "Alvin", 10}
user.Call()
reflectUser(user)
}
//反射获取对象属性
func reflectUser(input interface{}){
//获取对象的类型
inputType := reflect.TypeOf(input)
fmt.Println("Type is:", inputType)
inputValue := reflect.ValueOf(input)
fmt.Println("inputValue is:", inputValue)
//获取对象的属性, 并遍历
for i := 0; i < inputType.NumField(); i++ {
curField := inputType.Field(i)
fmt.Println("Field Type:", curField.Type)
fmt.Println("Field Name:", curField.Name)
fmt.Println("Field Value:", inputValue.Field(i))
}
}
反射解析结构体标签Tag
type Resume struct {
//tag和值之间一个冒号,不能有空格. 两个tag之间才是空格
Name string `info:"name" doc:"我的名字"` //后面的是Tag, 给反射用的
Sex string `info:"sex"`
}
func findTag(str interface{}) {
t := reflect.TypeOf(str).Elem()
for i := 0; i < t.NumField(); i++ {
infoTag := t.Field(i).Tag.Get("info")
docTag := t.Field(i).Tag.Get("info")
fmt.Println("info:", infoTag, "doc:", docTag)
}
}
func main() {
var re Resume
findTag(&re)
}
使用结构体Tag解析json文件实例
import (
"encoding/json"
"fmt"
)
type Movie struct {
Title string `json:title` //用tag指定json字段名称
Year int `json:year`
Price int `json:rmb`
}
func main() {
movie := Movie{"喜剧之王", 2000, 38}
//转json字符串
jsonStr, err := json.Marshal(movie)
if err != nil {
fmt.Println("Fail to convert json:", err)
return
}
//必须用printf才能格式化字符串
fmt.Printf("json str:%s\n", jsonStr)
//json还原对象
newMovie := Movie{}
err = json.Unmarshal(jsonStr, &newMovie)
fmt.Println(newMovie)
}
文章评论