详细 golang基础知识学习记录

简介: 详细 golang基础知识学习记录

 

go语言基础知识学习记录

go语言的基本语法:

注:参考 菜鸟教程 学习

  1. go run hello.go 直接运行,输出结果(原理也是编译后执行)
  2. go build hello.go 生成可执行程序,运行可执行程序,输出结果
  3. 注意 go语言中花括号不能单独占一行,否则会报错
package main
import "fmt"
func main(){ //go语言中此处的花括号不能单独占一行,否则会报错
    fmt.Println("hello world")
}
  1. go语言一条语句占一行,如果一行需要执行多个语句 使用 分号 隔开
  2. go语言的输出语句有3种方式
  1. import "fmt" 后适用fmt.Println(x) -- 输出
  2. println(x) -- 输出
  3. fmt.Printf("%d",x) -- 格式化输出

 

关键字

下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

break

default

func

interface

select

case

defer

go

map

struct

chan

else

goto

package

switch

const

fallthrough

if

range

type

continue

for

import

return

var

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

append

bool

byte

cap

close

complex

complex64

complex128

uint16

copy

false

float32

float64

imag

int

int8

int16

uint32

int32

int64

iota

len

make

new

nil

panic

uint64

print

println

real

recover

string

true

uint

uint8

uintptr

 

 

字符串的拼接和变量的定义方式

定义变量的三种方式

  1. 正常使用var定义变量
  2. 使用var定义变量,但是不定义类型,通过赋初值的方式,go编译器自动识别
  3. 使用:=的方式来进行 新变量的定义,仅限于新变量 -- 适用于定义在函数内部

 

//字符串 可以使用+ 进行拼接
  fmt.Println("this is my func")
  fmt.Println("hello ,wolrd" + "xiaozhuzhu")
//定义变量
  var  name string="qqqq"
  var age,tail int=24,170
  fmt.Println(name, age , tail)
  fmt.Println(name)
  fmt.Println(age)
  fmt.Println(tail)
//定义变量的三种方式
//1
  var a int = 1
  fmt.Println(a)
//2 使用var定义变量,但是不定义类型,通过赋初值的方式,go编译器自动识别
  var b = "hello"
  fmt.Println(b)
//3 使用:=的方式来进行 新变量的定义,仅限于新变量 
//:= 左侧如果没有声明新的变量,就产生编译错误
  c := 20
  fmt.Println(c)
  //c:=30 //报错,因为c已经不是新变量的
  c=30  //正确,是一个正常的赋值操作
  fmt.Println(c)
  c,d:=40,90 //这样是合法的
  fmt.Println(c,d)

因式分解的方式,仅仅适用于定义全局变量

 

//因式分解的方式,仅仅适用于定义全局变量
var
(
  g_a int = 1
  g_b,g_c int=1,2
)

 

空白符

空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。

_ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。

 

//空白符
  _,e := 2,3
  fmt.Println(e)

const常量

  • 定义const常量

 

//定义const常量
  const width,height = 10,5
  var area int=width*height
  fmt.Println("面积为", area)  //50
  • const常量用作枚举

 

const(
  unknow = 0
  man = 1
  woman = 2
)
println(unknow,man,woman)  //0 1 2
  • 常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:

 

const(
  a = "hello"
  b = len(a)
  c = unsafe.Sizeof(a)
)
println(a,b,c)  //hello 5 16

itoa的用法

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值:

 

//itoa的用法
const(
  g_a = iota
  g_b
  g_c
  g_d
)
const(
  g_e = iota
  g_f = "hello"
  g_g
  g_h = iota
  g_i
)
const(
  g_j = 1<<iota
  g_k
  g_l
  g_m
)
println(g_a,g_b,g_c,g_d)
println(g_e,g_f,g_g,g_h,g_i)
println(g_j,g_k,g_l,g_m)
//0 1 2 3
//0 hello hello 3 4
//1 2 4 8

运算符

go语言的运算符和C语言的运算符基本一致

Go 没有三目运算符,不能适用?:

算术运算符

关系运算符

逻辑运算符

位运算符

赋值运算符

其他运算符

 

语言条件语句

  • if xxx

 

if xxx {
    ...
}
  • if xxx {...} else{...}
if xxx{
    ...
}else{
    ...
}
  • if xxx{ ... if xxx { ...}}
if xxx{
    if xxx {
        ...
    }
    ...
}
  • switch
package main
import "fmt"
func main(){
  grade:= 90
  if grade >= 90{
    println("优秀")
  }else if grade >=70 && grade <90{
    println("良好")
  }else{
    println("差")
  }
  var x interface{} //计算类型
  switch i := x.(type){
    case nil:
    fmt.Printf(" x 的类型 :%T\n",i)
    case int:
    fmt.Printf("x 是 int 型")
    default:
    println("未知")
  }
}
  • select

 

for循环的方式

  • 三种方式
  1. 类似C语言中的for
  2. 类似C语言中的while
  3. 死循环

 

package main
import "fmt"
func main(){
//类似C语言中的for
  var sum int
  for i:=1;i<=10;i++{
    sum +=i
  }
  fmt.Println(sum)
//类似于while
  for sum >30{
    sum -= 10
    fmt.Println(sum)
  }
//死循环
for {
    ...
}
  • For-each range 循环

 

//for-each  range 循环的方式
  for i,str:= range name{
  fmt.Printf("%d -- %s\n",i,str)
  }
//0 -- qqqq
//1 -- yyyy

函数

go语言的函数,可以有多个返回值,其余和C语言没有什么区别

 

 

作用域

与C语言一致

  • 局部变量
  • 全局变量
  • 函数形参

 

数组

思想和C语言一致,写法如下:

 

name := []string{"qqqqq","yyyyy"}
nums :=[]int{1,2,3,4,5,6}

指针

 

var ptr1 *int

 

二级指针

 

var  a int
var ptr *int
var pptr **int
ptr = &a
pptr = &ptr

 

指针数组

 

var ptr [5]*int

 

结构体

go语言中的结构体变量,和结构体指针,访问结构体成员的时候,都是使用 点(.)来进行访问,如下:

 

//定义一个结构体
type info struct{
    name string
    age int
    height int
}
//使用
var stu info
stu.name = "qqqq"
stu.age = 24
stu.height = 170
fmt.Println(stu.name,stu.age,stu.height)
var stu2 *info = &stu
stu2.name = "yyyy"
stu2.age = 24
stu2.height = 160
fmt.Println(stu2.name,stu2.age,stu2.height)

 

切片slice

Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

  • 使用var定义
  • 定义空slice
  • 使用:=定义
  • 使用make来定义 make([]type,len,cap)
  • apend 和 copy的使用

 

package main
/*
    author:qqqq
    file:slice
    function:study slice for golang
*/
import "fmt"
func main(){
//定义切片的方式
//1、使用var定义
    var s1 = []int{1,2,3};
    printInfo(s1);
//2、定义空slice
    var s2 []int
    printInfo(s2);
//3、使用:=定义
    ss := []int{3,4,5,6}
    printInfo(ss);
//4、使用make来定义 make([]type,len,cap)
    s3 := make([]int,2,3)
    printInfo(s3);
//复制操作
    s3[0] = 3
    printInfo(s3);
//覆盖整个slice
    s1 = s3
    printInfo(s1);
//apend 和 copy的使用
    s3 = append(s3,6,7,8,9)
    printInfo(s3);
//扩容
    s4 := make([]int,len(s3),cap(s3) * 3)
    copy(s4,s3)
    printInfo(s4);
//s[2:]
    println(s4[1:])
    println(s4[:4])
    println(s4[1:3])
    fmt.Printf("s4[1:] = %v \n",s4[1:])
    fmt.Printf("s4[:4] = %v \n",s4[:4])
    fmt.Printf("s4[1:3] = %v \n",s4[1:3])
}
func printInfo(s[]int){
    fmt.Printf("len = %d, cap = %d, slic = %v\n",len(s),cap(s),s);
}

 

范围Range

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。

在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。

 

  • range 对于 数组、切片
  • 对于字符串
  • range对于map集合
  • 占位符_

 

package main
/*
    author:qqqq
    file:range
    function:study range for golang
*/
import "fmt"
func main(){
//1、range 对于 数组、切片
    s := []string{"apple","pen"}
    for i,value := range s{
        fmt.Println(i,value)
    }
//2、对于字符串
    for i,value := range "hello"{
        fmt.Println(i,value)
    }
//3、range对于map集合
    m := map[string]string{"name":"xiaopang","age":"25"}
    for i,value := range m{
        fmt.Println(i,value)
    }
//4、占位符_
    sum := 0
    nums := []int{1,2,3,4,5}
    for _,value := range nums{
        sum += value
    }
    fmt.Println(sum)
}

 

MAP集合

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

 

//类似于key-value的形式
map[string]string
m := map[string]string{"name":"xiaozhu","age":"15"}
mm := make(map[string]string)
countryCapitalMap [ "France" ] = "巴黎"
countryCapitalMap [ "Italy" ] = "罗马"
countryCapitalMap [ "Japan" ] = "东京"
countryCapitalMap [ "India " ] = "新德里"

delete() 函数

delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key

 

delete(countryCapitalMap,"France")

 

递归函数

Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。

递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等。

递归算阶乘

 

package main
import "fmt"
func fabulaqi(n uint 64) (result uint64){
    if n>0 {
        return fabulaqi(n-1)*n
    }
    return 1
}
func main(){
    fmt.Println("result : ",fabulaqi(15))
}

菲波拉契数列

 

func fabolaqi(n uint64)(result utin64){
    if n<2{
        return n
    }else{
        return fabolaqi(n-2)+fabolaqi(n-1)
    }
}

 

接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

 

package main
import "fmt"
//接口
type phone interface {
    call()
    show()
}
type xiaomi struct {
    name string
    ads  string
}
type huawei struct {
    name string
    ads  string
}
//接口实现
func (x xiaomi) call() {
    fmt.Println("phoneName :", x.name)
}
func (x xiaomi) show() {
    fmt.Println("advertisement :", x.ads)
}
func (h huawei) call() {
    fmt.Println("phoneName :", h.name)
}
func (h huawei) show() {
    fmt.Println("advertisement :", h.ads)
}
func main() {
    x := xiaomi{"mi note2", "for fire"}
    x.call()
    x.show()
    h := huawei{"hw p40", "your better phone"}
    h.call()
    h.show()
}

错误

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。error类型是一个接口类型,这是它的定义:

 

package main
import "fmt"
//定义数据结构
type DivideError struct {
    devidee int
    devider int
}
//错误处理实现Error()接口
func (de *DivideError) Error() string {
    strdata := `
        error,divide is zero
        dividee is %d
        divider is zero
    `
    return fmt.Sprintf(strdata, de.devidee)
}
//实现功能接口
func Divide(dividee int, divider int) (result int, errMsg string) {
    if divider == 0 {
        data := DivideError{dividee, divider}
        errMsg = data.Error()
        return
    } else {
        return dividee / divider, ""
    }
}
func main() {
    a := 10
    b := 0
    result, err := Divide(a, b)
    if err != "" {
        fmt.Println(err)
        return
    }
    fmt.Printf("%d / %d == %d \n", a, b, result)
}

 

go语言的并发

Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。goroutine 语法格式:

  • go的并发也是线程不安全的,需要加锁才安全

 

package main
import (
    "fmt"
    "time"
)
func say(s string) {
    var i int
    for i = 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}
var num int = 0
//goroutine 是线程不安全的
func countNum() {
    var i int
    for i = 0; i < 10; i++ {
        time.Sleep(5 * time.Millisecond)
        num++
    }
}
func main() {
    //go say("hello")
    //say("world")
    go countNum()
    countNum()
    fmt.Println(num)
}

通道(channel)

  • 通道(channel)是用来传递数据的一个数据结构。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
  • 注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。以下实例通过两个 goroutine 来计算数字之和,在 goroutine 完成计算后,它会计算两个结果的和:
  • 通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小
  • Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片

 

package main
import "fmt"
//不带缓冲的 通道
func getSum(s []int, c chan int) {
    sum := 0
    for _, value := range s {
        sum += value
    }
    c <- sum
}
func getSum2(c chan int, n int) {
    x, y := 0, 1
    var i int
    for i = 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c) //关闭通道
}
func main() {
    //不带缓冲的 通道
    // s := []int{3, 5, -2, 3, 4, 7, 1, 1, 1}
    // c := make(chan int)
    // go getSum(s[:3], c)
    // go getSum(s[3:6], c)
    // go getSum(s[6:], c)
    // x, y, z := <-c, <-c, <-c
    // fmt.Println(x, y, z, x+y+z)
//带缓冲的通道
    c := make(chan int, 10)
    go getSum2(c, cap(c))
    for value := range c {
        fmt.Println(value)
    }
}

自己调用别的包/自己的包

 

自己调用别人的包或者自己的包,如上目录结构

  • 自己写的包名,要和目录名一样

mylib.go

 

package mylib
func Add(a, b int) int {
    return a + b
}

main.go

package main
import (
    "fmt"
    "mystudy.com/mylib"
)
func main() {
    fmt.Println(mylib.Add(2, 3))
}

 

 

 

 

 

 

 

相关文章
|
缓存 机器人 Go
Golang 语言 beego 学习之安装和快速入门
Golang 语言 beego 学习之安装和快速入门
78 0
|
7月前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
2月前
|
安全 Java Go
【Golang入门】简介与基本语法学习
Golang语言入门教程,介绍了Go语言的简介、基本语法、程序结构、变量和常量、控制结构、函数、并发编程、接口和类型、导入包、作用域以及错误处理等关键概念,为初学者提供了一个全面的学习起点。
32 0
|
4月前
|
机器学习/深度学习 存储 人工智能
Golang bytes 包学习
Golang bytes 包学习
27 3
|
5月前
|
编译器 Go C语言
通过例子学习在golang中调试程序
【7月更文挑战第4天】Go语言支持使用cgo进行汇编调试,官方文档在golang.org/doc/asm。注意,调试Go运行时可能遇到变量不可用或行号错误,需谨慎使用step命令。
78 1
通过例子学习在golang中调试程序
|
7月前
|
Go
golang学习参考记录
golang学习参考记录
|
7月前
|
JSON Go 数据格式
golang学习7,glang的web的restful接口结构体传参
golang学习7,glang的web的restful接口结构体传参
|
7月前
|
JSON Go 数据格式
golang学习6,glang的web的restful接口传参
golang学习6,glang的web的restful接口传参
|
7月前
|
Java Go 开发工具
golang学习1,dea的golang-1.22.0
golang学习1,dea的golang-1.22.0
|
7月前
|
JSON Go 数据格式
golang学习5,glang的web的restful接口
golang学习5,glang的web的restful接口