详细 golang基础知识学习记录

本文详细记录了Go语言的基础知识,包括关键字、字符串拼接、变量定义、运算符、条件语句、循环、函数、作用域、数组、指针、结构体、切片、MAP集合、通道、错误处理、接口以及并发等内容,适合Go语言初学者参考学习。
摘要由CSDN通过智能技术生成

 

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))
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值