关于golang:GO基础知识分享

40次阅读

共计 8487 个字符,预计需要花费 22 分钟才能阅读完成。

[TOC]

GO 基础知识分享

兵长:哟,最近在干啥呢

胖 sir:在看我之前的 go 根底学习材料呢,回顾一下

兵长:那给我分享一下呗,我也想回顾回顾

胖 sir:用你的小手指点开你的手机,我来传给你

兵长:你信不信我的小手指能够带你飞整个峡谷 . . .

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="xiaomotong"
    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

iota 的用法

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

    相似于 C 语言中的 select,用于多路 IO 复用

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 循环的形式
    name := []string{"qqq","yyy"}
    for i,str:= range name{fmt.Printf("%d -- %s\n",i,str)
    }

//0 -- qqq
//1 -- yyy
------------------------------------------------------------------------
    str := []string{"北京", "天津", "山东"}

    // 能够默认丢掉第二个返回值
    for i := range str {fmt.Printf("%d -- %s\n", i, str[i])
    }

函数

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

作用域

与 C 语言统一

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

数组 & 切片

思维和 C 语言统一,数组是固定长度的

切片是动静扩容的,相似于 C ++ 的 vector

切片写法如下:

name := []string{"xiaomotong","pangsir"}

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 = "xiaomotong"
stu.age = 24
stu.height = 170

fmt.Println(stu.name,stu.age,stu.height)

var stu2 *info = &stu
stu2.name = "pangsir"
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:xiaomotong
    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:xiaomotong
    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 fabulaxiaomotong(n uint 64) (result uint64){
    if n>0 {return fabulaxiaomotong(n-1)*n
    }
    return 1
}

func main(){fmt.Println("result :",fabulaxiaomotong(15))
}

菲波拉契数列

func fabolaxiaomotong(n uint64)(result utin64){
    if n<2{return n}else{return fabolaxiaomotong(n-2)+fabolaxiaomotong(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)
    }

}

本人调用别的包 / 本人的包

本人调用他人的包或者本人的包,如上目录构造

  • 本人写的包名,要和目录名一样
  • 应用 go mod 模块,执行 go mod init mystudy

mylib.go

package mylib

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

main.go

package main

import (
    "fmt"
    "mystudy/mylib"
)

func main() {fmt.Println(mylib.Add(2, 3))
}

以上为本期全部内容,如有疑难能够在评论区或后盾提出你的疑难,咱们一起交换,一起成长。

好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享高兴

技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。

作者:小魔童哪吒

正文完
 0