目录
- 下载与资源
- 安装和配置
- 快速启动goland的方法
- liteide
- 基础
- 工程管理
- 变量
- 常量const
- 类型转换
- iota枚举
- 输出格式
- 接收输入
- 枚举iota
- 字符串处理
- if条件
- switch分支
- for循环
- 函数的不定参数
- 函数类型
- 函数返回值
- 匿名函数
- 闭包
- 递归函数
- 数组
- 遍历数组
- 切片
- map
- 结构体
- 指针变量
- 数组指针
- 切片指针
- 匿名字段
- 方法
- 接口
- 接口继承
- 空接口
- 多态
- 错误处理
- defer
- 文件
- 并行和并发
- goroutine
- channel
下载与资源
安装和配置
sudo tar -xzf go1.12.7.linux-amd64.tar.gz -C /usr/local
sudo vim /etc/profile
export GOPATH=/home/jiangzhibin/golang
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
source /etc/profile 使得其配置文件有效
//gopath
echo $GOPATH
gppm下载包
快速启动goland的方法
1. 创建一个根链接,goland
sudo ln -s /home/jiangzhibin/soft/goland/bin/goland.sh /usr/bin/goland
2. 开机自动启动
终端: gnome-session-properties
添加命令: goland
liteide
/home/jiangzhibin/soft/liteidex37.4.linux64-qt5.5.1/liteide/bin/liteide
sudo ln -s /home/jiangzhibin/soft/liteidex37.4.linux64-qt5.5.1/liteide/bin/liteide /usr/bin/liteide
基础
//导入主函数的包
package main
import "fmt"
// 单行注释
/*
块注释
*/
func main() {
//程序有且只有一个主入口
fmt.Println("hello world go!")
fmt.Println("tiantian!")
}
工程管理
src工作目录 main包 主函数
函数是全局的,还有全局变量,都可全局使用。
不同级目录,包名用目录名,函数首字母大写。
主函数如果调用不同级目录中的函数要导入这个包:
如下图所示:
import "userinfo"
func main(){
userinfo.Login()
}
pkg目录,系统生成的归档文件
bin目录,源码生成的可执行文件
变量
//内存地址的别名
var 变量名 数据类型 声明
var 变量名 数据类型 值
变量名 := 值 //自动推导类型
var a int = 10
var r float64 = 2.5
//自动推导类型, 注意只能在函数内使用
//会自动为变量选择类型
r := 3.256
a,b,c,d := 10,20,30,60
//匿名变量 _ ,占位但不接受值
a,_ := 1,20
不同的数据类型不能计算
// * 指针运算符,取出地址中的值
var a int = 10
p := &a
*p //p是指针变量
常量const
常量的值不允许修改,一般大写字母表示,存储在数据区,变量存储在栈区。
常量不能用&来引用
const A int = 20
//字面常量,程序中的硬编码常量
直接数字 或 字符串
类型转换
var a int = 10
var b float64 = 2.44
c := float64(a) * b
iota枚举
常量声明可以使用常量生成器初始化。
const (
a = iota
b = iota
c = iota
)
输出格式
fmt.Println("hello world") //输出并换行
a := 10
b := "zhansan"
fmt.Printf("数据是:%d ,名字是:%s ", a, b) //格式化输出
%d 整形 %f 浮点型 %t 布尔型 %s 字符串 %c 字符类型 %p 内存地址 \n 换行
接收输入
var a int
fmt.Scan(&a)
fmt.Scanf("%d%s", &a,&b) //格式化输入
枚举iota
声明一组相似的常量,值会递增
const (
a = iota //0
b = iota //1
c = iota //2
)
字符串处理
import (
"fmt"
"strings"
)
func main() {
str := "hello world"
res := strings.Contains(str, "he")
fmt.Println(res)
}
if条件
var a = 10
var b = 20
if a < b {
fmt.Println("true!")
}
if a < b {
}else if a = b{
}else {
}
switch分支
var a int
fmt.Scan(&a)
switch a {
case 1:
fmt.Println("monday")
case 2:
fmt.Println("tuesday")
}
for循环
var a int
for a = 1; a < 20; a++ {
fmt.Println("tongtong")
}
//break 跳出本层循环
//continue 结束本次循环,继续下次循环
goto
函数的不定参数
可以接受多个参数
func test(args ...int){
fmt.Printf(args)
}
test(1,2,3)
len()计算不定参的长度,len(args)
函数类型
其实是一个指针,在代码区存储
函数是全局的,可以被项目中的所有文件调用,所以函数名是唯一的。
type funcdemo func()
type functest func(int int) /带参数
type functt func(int int)int /带返回值
函数返回值
//单个返回值
func add(a int, b int) int {
return a + b
}
//多个返回值
func add(a int, b int) (int, int) {
return a + b, a - b
}
匿名函数
func() {
fmt.Println("hello")
}()
闭包
函数的返回值是一个函数,实现函数在栈区的本地化。
func test2() func() int{
var a int
return func() int{
a++
return a
}
}
递归函数
本身调用自己的函数
func test3(){
if i < 3{
test3()
}
}
数组
var 数组名 [元素个数]数据类型
var arr1 [10]int
遍历数组
for range 可以遍历集合、数组、切片、map中的数据, for的另一种写法
for i, data = range array1
for _,data = range arr{
sum += data
}
切片
一般不直接使用数组,使用切片slice
不写元素个数是切片,必须写元素个数的是数组。
切片是视图类型view
arr := [...]int{0, 1, 3, 10, 52, 30, 3}
s := arr[2:6]
var s []int = []int{1,2,3,4}
s = append(s,5,6) //追加数据
slice := s[1:] //切片取值,从下标是1开始到结尾
s := make([]int, 5)
s[0] = 1
map
字典结构类型,键值对存储:key->value
var m map[int]string
m := make(map[string]int)
m := make(map[int]string)
m[12] = "hello"
m[1] = "wowu"
m := map[int]string{
1:"zhangsan",
2:"lisi",
3:"wangwu",
}
m := map[string]string {
"name": "zhangsan",
"site": "baidu.com"
}
// for... range遍历
for k, v := range m {
fmt.PrintLn(k, v)
}
//删除元素
delete(m, "name")
结构体
go仅支持封装,没有class, 不支持继承和多态
类似于类的概念,于函数外定义,全局作用域
type treeNode struct {
value int
left, right *treeNode
}
type Student struct {
id int
name string
sex string
age int
addr string
}
var s Student
s.id = 1
s.name = "zhangsan"
s.age = 20
//或者这样定义
var s Student = Student{id: 1, name: "lisi", sex: "male", age: 20}
s := Student{id:1, name:"zhangsan", age:18}
//结构体数组
var arr [5]Student
arr[0].id = 1
arr[0].name = "hello"
arr[1] = Student{id: 1, name: "lisi", sex: "male", age: 20}
//
type treeNode struct {
value int
left, right *treeNode
}
func main(){
var root treeNode
root = treeNode{value: 3}
root.left = &treeNode{}
root.right = {5, nil, nil}
root.right.left = new(treeNode)
}
指针变量
基本类型前加 * ,可以通过指针访问变量和赋值
指针不能运算, go只有值传递
值传递就是直接拷贝数值, 引用传递是地址拷贝
var a = 10
var p *int //空指针
//p = oxf589 野指针, 指针定义后不能直接赋值,直接赋值为野指针
p = &a
*p / == a
//指针空间 在堆区创建空间
var p *int
p = new(int)
//两个变量互换值
//以下的方法不会改变
func swap(a, b int){
a, b = b, a //结果不会改变
}
//需要使用指针的办法
func swap(a, b *int){
*a, *b = *b, *a
}
//或者将数据返回
func swap(a, b int) (int, int){
a, b = b, a
return a, b
}
数组指针
可以直接使用指针操作数组元素
var arr [5]int = [5]int{1,2,3,4,5}
var p *[5]int
p = &arr
fmt.Printf("%T", p) // *[5]int
p[0] //arr[0] 1
len(p) //也可以获取数组的长度
切片指针
和数组指针类似,但有区别
var slice []int = []int{4, 12, 12, 6}
var p *[]int
p = &slice
(*p)[0] //slice[0] 4
匿名字段
实现继承操作,结构体嵌套结构体
type person struct {
name string
sex string
age int
}
type Student struct {
person
id int
score int
}
func main() {
var stu1 Student
stu1.id = 1
stu1.name = "zhangsan"
fmt.Println(stu1)
}
//或者这样初始化
var stu1 Student = Student{person{"zhangsan", "male", 18}, 1, 60}
//如果有同名字段,则用子类(就近原则),或者使用父类名初始化。
stu1.person.name = "zhangsan"
方法
为对象绑定方法,和函数类似,但也有不同。
type Int int //为基本类型取别名,因为基本类型不能绑定方法
//func (方法授受者) 方法名(参数列表) 返回值类型
func (a Int) add(b Int) Int {
return a + b
}
func main() {
var a Int = 10 //根据数据类型,绑定方法
value := a.add(15)
fmt.Println(value)
}
//结构体绑定方法
type Student struct {
name string
age int
}
func (s Student) PrintInfo() { //结构体绑定方法 PrintInfo
fmt.Println(s.name)
}
func main() {
var s Student = Student{"zhangsan", 18}
s.PrintInfo()
}
接口
//接口方法只定义不实现
type Human interface {
sayHello()
}
type Person struct {
name string
age int
}
func (alice *Person) sayHello() {
fmt.Println("hello world", alice.name)
}
func main() {
var bob Person = Person{"alice", 18}
var h Human = &bob
h.sayHello()
}
接口继承
type Human interface { //子集
sayHello()
}
type Person interface { //超集
Human //一组子集的集合
dance()
}
空接口
空接口可以接受任意类型数据
var i interface {}
i = 10
i = "hello world"
多态
多态是将接口类型作为函数参数,多态实现了接口的统一处理
type Human interface {
sayHello()
}
type Person struct {
name string
age int
}
func (alice *Person) sayHello() {
fmt.Println("hello world", alice.name)
}
func sayHello(h Human) {
h.sayHello()
}
func main() {
var bob Person = Person{"alice", 18}
var h Human = &bob
// h.sayHello()
sayHello(h)
}
错误处理
errors panic recover
//可以从panic中获取控制权
defer func(){
recover()
}()
defer
延迟调用
defer func
文件
import (
"fmt"
"os"
)
fp, _ := os.Create("./test.txt")
fp.WriteString("hello golang!")
defer fp.Close()
并行和并发
并行:有两队同时使用两台咖啡机。 在同一时刻,有多个任务在多个处理器上同时进行。
并发:有两队同时轮流使用一台咖啡机。
goroutine
协程goroutime, 轻量级线程,
go关键字,开一个子协程,
主协程退出了,其它子协程也会退出,
非抢占式多任务处理,由协程主动交出任务权
package main
import (
"fmt"
"time"
)
func newTask() {
for {
fmt.Println("new task")
time.Sleep(time.Second)
}
}
func main() {
go newTask()
for {
fmt.Println("hello main")
time.Sleep(time.Second)
}
}
//
func main() {
for i := 0; i < 1000; i++ {
go func(i int) { //并发
for {
fmt.Printf("hello2\n", i)
}
}(i)
}
time.Sleep(time.Millisecond)
}
//让别的协程先执行
runtime.Gosched()
channel
make(chan type) //无缓存的通道
make(chan type, capacity) //有缓存的通道
close(channel) //关闭通道
eg:
channel <- value //发送value到channnel
<- channel //接受并弃用
x := <- channel //从channnel接受并赋值给x
x, ok := <- channel //功能同上,同时检查通道是否关闭或为空
func chanDemo() {
c := make(chan int)
go func() {
for {
n := <-c
fmt.Println(n)
}
}()
c <- 1
c <- 2
time.Sleep(time.Millisecond)
}
//bufferedChannel 构建缓冲区
c := make(chan int, 3)