Categorygithub.com/dollarkillerx/Golang-Study
module
0.0.0-20190522154747-1bf6fff96842
Repository: https://github.com/dollarkillerx/golang-study.git
Documentation: pkg.go.dev

# README

Golang-Study

Golang Study

gob

vim /etc/profile
export GOROOT=/opt/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=$HOME/goproject

hello golang

package main

import "fmt"

func main(){
    fmt.Print("Helo Golang!")
}

go run hello.go 编译并运行

$GOPATH 约定三个子目录

  • src 存放源代码(.go .c .h .s)
  • pkg 编译后生成的文件 (.a)
  • bin 编译后生成的可执行文件
go get github.com/beego/bee  #网站/开发者/package
$GOPATH/src/github.com/beego/bee

Basics

  • 特色 select go chan
  • 基础结构
import "main" //程序所属包
import "fmt" //导入依赖包
const MANE string = "dollarkiller" //const常量
var age = 20 //全局变量

//一般类型声明
type ageInt int
//结构体声明
type Dollar struct {
}
//声明接口
type IDollar interface {
}
//函数定义
func Dor() {
    fmt.Print("DollarKiller")
}
//main()入口函数
func main() {
    Dor()
    fmt.Println("GOLANG")
}

  • package
    package <pkgName>
    package main
    >>>
    main.main()函数独立程序入口点
    生成go可执行文件,必须要有main的package,且下必须要有main()函数
    同一个路径下只能存在一个package,一个package可以拆分成多个源文件
  • import

在 Go 中,首字母大写的名称是被导出的。

import 只能导入有package的包
不能导入源文件没有用到的包,否则会报错
语法格式1:
import "package1"
import "package2"
语法格式2:
import (
    "package1"
    "package2"
    ...
)
- import 原理
```
1.如果一个main导入其他的包,包将被顺序导入;
2.如果导入的包中依赖其他包(包B),会首先导入包B,然后初始化B包中的常量变量,最后执行B包中的init()
3.所有包导入完成后才会对main中的常量和变量进行初始化,然后指向main中的init函数(如何存在),最后执行main函数
4.如果一个包被导入多次这该包只会被导入一次 
```

import

  • var 定义 var varName type 蛤,和es5好像 定义了不用也会报错
func main(){
	var x int
	x = 1
	y,z := "DollarKiller","golang" //无法用于函数外部
	fmt.Printf("%d,%s,%s",x,y,z)
}
  • const 常量
  • int8 int16 int32 int64
  • byte
  • uint8 uint16 uint32 uint64 unsigned 无符号
  • float32 float64
  • complex 复数
  • string
  • array元组(静态) slice列表(动态)
  • map hash字典

任何数据类型以value形式输出fmt.Printf("%v",x)

  • import
    • 别名 别名 "fmt"
    • 省略调用 . "fmt" 就可以直接用fmt的方法了 [不建议]
    • 只执行导入包的init方法 _ "fmt"
package main

import (
    别名 "fmt"
    .    "fmt"
    _    "fmt"
)
  • 可见性规则

GO语言中,使用大小写来决定 常量,变量,类型,接口,结构 或函数是否可以被外部所调用

  • 函数名首字母 小写 即为provate
  • 首字母大写 为public

类型和变量

  • 常量的定义
const (
    PI = 3.14
    const1 = "1"
)
  • 变量的定义
    • 可以放在函数内,或直接放在包内 golang没有全局变量的概念
    • := 写的短一点
var (
    name = "dolalrkiller"
    age = 20
)
  • 一般类型声明
type (
    newType int
    type1 fload32
)
  • 基础类型
bool 长度1 只有true false  0 1不能表示
  • iota 自增值
func enums() {
    const {
        cpp=inta
        java
        _
        python
        php
        golang
    }
    fmt.Println(cpp,java,python,php,golang)
    >为0 1  3 4 5 注释_是跳过
}
  • >> << 左移运算符"<<“是双目运算符。左移n位就是乘以2的n次方。 右移运算符">>“是双目运算符。右移n位就是除以2的n次方。

条件语句

  • if if里面的变量具有作用域 外面要被调用必须return
package main
func bounded (v int) int {
    if v>100{
        return 100
    } else if v<0 {
        return 0
    } else {
        return v
    }
}

import (
	"fmt"
	"io/ioutil"
)

func main() {
	const filename = "abc.txt"
	contents,err := ioutil.ReadFile(filename)
	if err !=nil {
		fmt.Print(err)
	} else {
		fmt.Printf("%s\n",contents)
	}
}
  • if奇淫技巧
if contents,err := ioutil.ReadFile(filename);err!=nil {
    fmt.Printf("%s\n",contents)
}else {
    fmt.Print(err)
}
  • switch 会自动break
func eval(a,b int,op string) int {
	var result int
	switch op {
	case "+":
		result = a+b
	case "-":
		result = a-b
	case "*":
		result = a*b
	case "/":
		result = a/b
	default:
		panic("unsupported operator" + op)
	}
	return result
}
  • switch pro //panic终端服务指向 并且 报错
func grade(score int) string {
	g := ""
	switch {
	case score<0 || score>100:
		panic(fmt.Sprintf("Wrong score:%d",score))
	case score>80:
		g = "a"
	case score>60:
		g = "b"
	case score<60:
		g = "f"
	}
	return g
}
  • for
func converToBin(n int){
	for s :=0 ;s<n;s++{
		fmt.Println(s)
	}
}
  • while 没有了哈哈
for 判断 {
    内容
}

for  {
    死循环
}
  • 函数 (函数可以作为参数 没有默认参数,可选参数)
func funcName(x,y int) (x,y int) {
    return 
}

func funcName(x,y int) (int,int) {
    return x,y
}

func sum(number ...int) int {
    s := 0
    for i := range number {
        s += number[i]
    }
}

func sun (op func(int,int) int,a,b int) int {
    
    return op(a,b)
}

传入函数

func apply(函数名称 函数体 返回类型,..) {
    
}

func apply(op func(int.int) int,a,b,int) int {
    return op(a,b)
}

指针

var a int = 2
var pa *int = &a
*pa = 3
fmt.Println(a)

指针不能运算

数组,切片,容器

  • 数组
func main() {
	var arr1 [5]int // 初始值0
	arr2 := [3]int{1,3,5} // :=必先初始化
	arr3 := [...]int{2,4,6,8,10} // 定义切片
	var grid [4][5]int // 定义四行五列

	fmt.Print(arr1,arr2,arr3,grid)
}
  • 数组遍历
    for i := 0; i<len(arr3);i++  {
		fmt.Print(arr3[i]," ")
	}

	for k,v := range arr3 { // 下标 value  if 只有k就只要下标
		fmt.Println("key: ",k,"value: ",v)
	}

	for _,v := range arr3 {
		fmt.Print(v)
	}

注意

[10]int [20]int是不同类型
调用func f(arr [10]int) 是值传递
  • Slice切片 实现机制视图
arr := [...]int{0,1,2,3,4,5,6,7,8,9}
s := arr[2:6] // 前闭后开

切片是引用传递 Slice本身没有数据,是对应底层array的一个view

func updateSlice(s []int) {
	s[0] = 110
}

func main()  {
	arr := [...]int{0,1,2,3,4,5,6,7,8,9}
	a := arr[2:6]
	b := arr[2:] // 从2去到最后
	c := arr[:6] //  从头开始取6个
	d := arr[:] // 全部
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)
}

func mm() {
	s := [10]int{0,1,2,3,4,5,6,7,8,9}
	s1 := s[2:6] // 2,3,4,5
	s2 := s1[4:6] // 6,7
	fmt.Println(s2)
}

fmt.Printf("arr= %v len(arr)= %d cap(arr)=%d",a,len(a),cap(a)); - 添加元素 append(s2,10) 在最后加入 - append if超越cap系统会分配更大的底层数组 原来的数组没有用就会被回收掉 - 指定len cap s3 := make([]int,len,cap) s2 := make([]int,16,20) fmt.Println("value" , s2 , len(s2), cap(s2)) - copy - copy(拷贝到,拷贝的内容) 例如copy(s2,s1) 把s1 copy到s2最前面 - 删除 - 删除指定元素 - s2 = append(s2[:3],s2[4:]...)

Map 无序

  • 定义
func main()  {
	m := map[string]string {
		"name": "dollarkiller",
		"age": "18",
		"course": "golang",
	}
	fmt.Print(m)
}

注释 用没有定义的返回 空

    if cases,ok := m["case"];ok {
        fmt.Println(cases)
    }else {
        fmt.Printlb("key is not exist")
    }
	fmt.Println(cases,ok)
    // ok 存在返回true 反之else
  • 删除 delete(map,key)
    if name,ok := m["name"];ok {
        delete(m,"name)
    }

注释 定义 := if 定力了用更改等操作用=

  • 小结
    • 创建 make(map[string]int)
    • 获取元素 m[key]
    • 当key 不存在时,获得value类型的初始值
    • value,ok := m[key] 用ok判断是否存在
    • delete(m,key)
    • 遍历 k,v := range map
      • 不保证便利顺序 需要手动对key排序
      • 使用len获得元素个数
  • map的key
    • map使用hash表,必须可以比较相等
    • 除了slice,map,func的内建类型都可以作为key
    • struct类型不包含上述字段,也可以作为key
  • 使用 utf8.RuneCountInString 获得str数量
  • 使用len获得字节长度
  • 使用[]byte 获得字节

结构体和方法

  • 尽支持分装,不支持继承和多态
  • 不论地址还是结构本身,一律使用.来访问成员
  • 当默认构造不能满足要求的时候可以使用工厂函数
    • 工厂函数返回局部变量的地址
    • 不需要知道 堆栈分配
      • 返回引用地址 在堆上分配
      • 没有返回引用地址 在栈上分配
func createNode(value int) *treeNode {
	return &treeNode{value: value}
}
  • 结构方法
    • 指针才可以改变结构内容
    • nil 指针也可以调用方法
    • 值接受者 vs 指针接受者
      • 需要改变内容必须使用指针接受者
      • 结构过大也考虑使用指针接受者
      • 一致性: 如有指针接受者,最好都是指针接受者
  • 匿名字段
type Human struct {
    name string
    age int
    weight int
}

type Student struct {
    Human // 匿名字段,默认包含human所有字段
}

封装

  • 名字一般使用CamelCase
  • 首字母大写:public
  • 首字母小写:private
    • 每个目录一个包
    • main包包含可执行入口
    • 给结构定义方法必须放在同一个包内
    • 可以是不同文件
  • 扩充系统类型or其他类型
    • 定义别名
    • 使用组合
// 接受者 (接受者) 返回函数名称
func (node treeNode) print() {
	fmt.Println(node)
}
root.print()

接口 非侵入式接口

在golang中 一个类实现了该接口要求的所有的函数,这个了类就实现了该接口 - 将对象实例赋值给接口 - 将接口赋值给接口 小=大 可以把包含方法多的接口赋值给包含方法少的接口 - go语言的任何类型都可以实现空接口

type Animal interface {
    Eat()
    Fly() bool
}
type Bird struce {}

func (bired Bird) Eat() {
    fmt.print("birde Eat")
}
func (bired Bird) Fly() bool {
    return true
}
func main() {
    animal := new(Animal)
    bired := new(Bird)
    animal = bired
    animal.Fly()
    animal.Eat()
}
  • 空接口 空接口可以接受任何对象
var v1 interface{} = 1
var v1 interface{} = "abc"
var v1 interface{} = 2.56
var v1 interface{} = make(map..)
  • 空接口 类型查询
if v,ok :=v1.(float64);ok {  // 判断v1是不是float64
    fmt.Print("this is float64")
}
var v1 interface{}
v1 = 65.45
switch v := v1.(type) {
    case int:
        ..
    case float32:
        ..
}

GOPATH

  • 默认在~/go(unix,linux),%USERPROFILE%\go
  • 官方推荐:所有的项目和第三方库都放到同一个GOPATH下
  • 也可以将每个项目放到不同的GOPATH

duck typing

  • 描述事物的外部行为而非内部结构
  • 严格说go属于结构化类型系统,类似duck typing

并发编程 协程

协程 轻量级 创建上百万个都不会挂掉 而线程和进程不能超过1万个

  • goroutine-Go对协程的实现
    • go + 函数名: 启动一个协程执行函数体

channel

Go语言在语言级别提供goroutine之间的通讯方式

  • 声明 var chanName chan ElementType
    • 利用make定义 可以指定chan容量
  • channel写和读
    • ch <- c写
    • c:=<-ch 读
    • 阻塞 除非有goroutine对其进行操作

golang指南

基础

  • 多值返回
package main

import "fmt"

func swap(s,y string) (string,string) {
	return s,y
}
//函数可以返回任意数量的返回值
func main() {
	a,b :=swap("hello","golang")
	fmt.Println(a,b)
}
  • 命名返回值
package main

import "fmt"

func split(sum int) (x,y int) {
	x = sum * 4 / 9
	y = sum -x
	return 
}
//命名返回值  golang返回值可以命名 没有参数的return 返回结果当前值`


func main() {
	fmt.Println(split(17))
}
  • 变量var bool默认值 false 0
package main

import "fmt"

var cpp, python,php,java bool
//定义在func外面为全局变量
func main() {
	var i int
	//定义在func内为局部变量 
	fmt.Println(i,cpp,python,php,java)
}

  • := 简洁赋值语句
package main

import "fmt"

func main() {
	var i,j int = 1, 2
	c,python,java,php := true,true,false,"ok!"
	//在函数中可以使用 `:=` 简洁赋值语句在明确类型的地方可以用于替代var定义  BUT在函数体外必须以关键字开始 `:=`不能用于函数体外
	fmt.Println(i,j,c,python,java,php)
}

  • 基础类型

golang占位符 https://studygolang.com/articles/2644

package main
  
import (
        "fmt"
        "math/cmplx"
)

var (
        ToBe bool = false
        MaxInt uint64 = 1<<64-1
        z complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
        const f = "%T(%v)\n"
        fmt.Printf(f,ToBe,ToBe)
        fmt.Printf(f,MaxInt,MaxInt)
        fmt.Printf(f,z,z)
}
// 别名 byte//uint8  rune //int32 代表一个Unicode码

//变量的定义可以打包在一个语法块中:
  • 零值

变量在定义时没有明确的初始化时会赋值为零值 数组类为0 布尔类为false 字符串类为"" 空字符串

  • 类型转换
var i int = 24
var f float64 = float64(i)
var u uint = uint(float64)

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author