首页 > 其他 > 详细

Go基础

时间:2020-05-22 20:57:50      阅读:68      评论:0      收藏:0      [点我收藏+]

Go语言的基础组成-->包声明/引入包/函数/变量/语句&表达式/注释

package main  
-->定义了包名,必须在源文件中非注释的第一行指明这个文件属于哪个包。package main表示一个
可独立执行的程序,每个Go应用程序都包含一个名为main的包
import
"fmt" -->告诉Go编译器这个程序需要使用fmt包(的函数,或其他元素),fmt包实现了格式化IO
(输入/输出)的函数

-->func main()是程序开始执行的函数。main函数是每一个可执行程序所必须包含的,一般都是在
启动后第一个执行的函数,如果有init()函数会先执行该函数
func main() { // --》 { 不能放在单独的行上
/*注释*/ fmt.Println("Hello, world!") }

当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,那么使用这种形式的
标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包)-->导出,像面向对象
语言中的public
标识符如果以小写字母开头,则对包外是不可见的,但在整个包的内部是可见并且可用的-->protected

运行go代码-->go run hello.go

生成二进制文件-->go build hello.go --> .exe

 

Go语言基础语法

Go标记:Go程序可以由多个标记组成,可以是关键字、标识符、常量、字符串、符号

 

Go语言数据类型

布尔型-->var b bool = true

数字类型 --> int  float32 float64

字符串类型 -->

派生类型-->指针类型Pointer、数组类型、结构化类型struct、Channel类型、函数类型、切片类型、接口类型interface、Map类型

 

声明变量使用var关键字,var identifier type

package main
import "fmt"
func main() {
    var a string = "Runoob"
    fmt.Println(a)

    var b, c int = 1, 2
    fmt.Println(b, c)
}
package main

var x, y int
var (  //这种因式分解关键字的写法一般用于声明全局变量
    a int 
    b bool   
)

var c, d int = 1, 2
var e, f = 123, "hello"


func main() {
    g, h := 123, "hello"
    println(x, y, a, b, c, d, e, f, g, h)
}

 

值类型和引用类型

int、float、bool、string这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值

可以通过&i来获取变量i的内存地址。值类型的变量的值存储在栈中

一个引用类型的变量r1存储的是r1的值所在的内存地址,或内存地址中第一个字所在的位置

 

使用变量的首选形式  :=

全局变量允许声明但不使用,局部变量声明了就必须使用否则报错

交换两个变量的值,可以使用a,b = b,a

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

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

 

Go语言常量

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型

常量定义:const identifier [type] = value

可以省略类型说明符[type],因为编译器可以根据变量的值来推断其类型

package main

import "fmt"

func main() {
    const LENGTH int = 10
    const WIDTH int = 5
    var area int
    const a, b, c = 1, false, "str"

    area = LENGTH * WIDTH
    fmt.Printf("面积为:%d", area)
    println()
    println(a, b, c)
}
//常量还可以用作枚举
const (
Unknown = 0
Female = 1
Male = 2
)
//常量可以用len(),cap(),unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过

package main

import "unsafe"

const (
    a = "abc"
    b = len(a)  //3
    c = unsafe.Sizeof(a)  //16
)

func main() {
    println(a, b, c)
}

iota

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

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

iota可以被用作枚举值

const (
a = iota
b = iota
c = iota
)

 

Go语言运算符

Go语言条件语句

Go语言循环语句-->

for循环

goto语句,go语言的goto语句可以无条件地转移到过程中指定的行。goto语句通常与条件语句配合使用,可用来实现条件转移,构成循环,跳出循环体等功能

无限循环,for true

 

Go语言函数

函数是基本的代码块,用于执行一个任务

Go语言最少有个main函数

函数声明告诉了编译器函数的名称,返回类型,和参数

函数定义:  func function_name([parameter list]) [return_types] {函数体}

func-->函数由func开始声明

function_name-->函数名称,函数名和参数列表一起构成了函数签名

parameter list-->参数列表

return_types-->返回类型

//函数返回两个数的最大值
func max(num1, num2 int) int {
    //声明局部变量
    var result int
    
    if (num1 > num2) {
        result = num1
    } else {
        result = num2
    }
    return result
}

闭包

package main

import "fmt"

func getSequence() func() int{
    i := 0
    return func() int {
        i += 1
        return i
    }
}

func main() {
    nextNumber := getSequence()
    /*调用nextNumber函数,i变量自增1并返回*/
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())
    fmt.Println(nextNumber())

    /*创建新的函数nextNumber1,并查看结果*/
    nextNumber1 := getSequence()
    fmt.Println(nextNumber1())
    fmt.Println(nextNumber1())

}

 

Go语言函数方法

Go语言中同时有函数和方法。一个方法就是一个包含了接收者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针

package main

import (
    "fmt"
)

/*定义结构体*/
type Circle struct {
    radius float64
}

func main() {
    var c1 Circle
    c1.radius = 10.00
    fmt.Println("圆的面积 = ", c1.getArea())
}

// func (variable_name variable_data_type) function_name() [return_type] {/*函数体*/}
func (c Circle) getArea() float64 {
    return 3.14 * c.radius * c.radius
}

 

Go语言变量作用域

Go语言中变量可以在三个地方声明:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

局部变量-->在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量

全局变量-->在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用

Go语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑

形式参数-->作为函数的局部变量来使用

package main

import "fmt"

/*声明全局变量*/
var a int = 20;

func main() {
    var a int = 10
    var b int = 20
    var c int = 0

    fmt.Printf("main()函数中 a = %d\n", a)
    c = sum(a, b)
    fmt.Printf("main()函数中c = %d\n", c)
}

func sum(a, b int) int {
    fmt.Printf("sum()函数中a = %d\n", a)
    fmt.Printf("sum()函数中b = %d\n", b)

    return a + b
}

 

Go语言数组

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形、字符串或者自定义类型

Go语言数组声明需要指定元素类型及元素个数-->var variable_name [SIZE] variable_type

 

Go语言指针

变量是一种使用方便的占位符,用于引用计算机内存地址

Go语言的取地址符是&,放到一个变量前使用就会返回相应变量的内存地址

指针-->一个指针变量指向了一个值的内存地址

var ip *int

 

使用指针:定义指针变量-->为指针变量赋值-->访问指针变量中指向地址的值

package main

import "fmt"

func main() {
    var a int = 20
    var ip *int

    ip = &a

    fmt.Printf("a变量的地址是:%x\n", &a)

    /*指针变量的存储地址*/
    fmt.Printf("ip变量储存的指针地址:%x\n", ip)

    /*使用指针访问值*/
    fmt.Printf("*ip变量的值:%d\n", *ip)

}

 

Go空指针

当一个指针被定义后没有分配到任何变量时,它的值为nil

一个指针变量通常缩写为ptr

 

指向指针的指针

如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量

Go语言指针作为函数参数

Go语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可

 

Go语言结构体

Go语言中数组可以存储同一类型的数据,但在结构体中可以为不同项定义不同的数据类型

定义结构体:使用type和struct语句

struct语句定义一个新的数据类型,结构体中有一个或多个成员

type语句设定了结构体的名称

type struct_variable_type struct {
    member definition
    member definition
    ......
    member definition
}
package main

import "fmt"

type Books struct {
    title string
    author string
    subject string
    book_id int
}

func main() {
    //创建一个新的结构体
    fmt.Println(Books{"Go 语言", "www.runoob.com", "Go", 12})
    //可以使用key=>value格式
    fmt.Println(Books{title: "Go 语言", author:"www.run.com", subject:"Go", book_id: 00})

}

访问结构体成员-->

结构体.成员名

结构体作为函数参数-->

可以向其他数据类型一样将结构体类型作为参数传递给函数

结构体指针-->

可以定义指向结构体的指针  var struct_pointer *Books

使用结构体指针访问结构体成员,使用“.”操作符

 

Go语言切片-->动态数组

Go语言切片是对数组的抽象,与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

定义切片-->可以声明一个未指定大小的数组来定义切片

var identifier []type

切片不需要说明长度,或使用make()函数来创建切片

var slice1 []type = make([]type, len)

或者

slice1 := make([]type, len)

len()和cap()函数

切片是可索引的,并且可以由len()方法获取长度

切片提供了计算容量的方法cap()可以测量切片最长可以达到多少

 

append()和copy()函数

如果想增加切片的容量,必须创建一个新的更大的切片并把原分片的内容都拷贝过来

 

Go语言范围Range

Go语言中range关键字用于for循环中迭代数组、切片、通道或集合的元素,在数组和切片中它赶回元素的索引和索引对应的值,在集合中返回key-value对

package main

import "fmt"

func main() {
    nums := []int{2, 3, 4}
    sum := 0
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)
    
    for i, num := range nums {
        if num == 3 {
            fmt.Println("index: ", i)
        }
    }
    
    kvs := map[string] string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }
    
    for i, c := range "go" {
        fmt.Println(i, c)
    }
}

Go语言Map

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

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

 

定义Map

可以使用内建函数make也可以使用map关键字来定义Map

//声明变量,默认map是nil
var map_variable map[key_data_type]value_data_type

//使用make函数
map_variable := make(map[key_data_type]value_data_type)
package main

import "fmt"

func main() {
    var countryCapitalMap map[string]string
    countryCapitalMap = make(map[string]string)
    
    //map插入key-value对
    countryCapitalMap["France"] = "巴黎"
    countryCapitalMap["Italy"] = "罗马"
    countryCapitalMap["Japan"] = "东京"
    countryCapitalMap["India"] = "新德里"
    
    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap[country])
    }
    
    //查看元素在集合中是否存在
    capital, ok := countryCapitalMap["American"]
    
    if (ok) {
        fmt.Println("American的首都是", capital)
    } else {
        fmt.Println("American的首都不存在")
    }
    
    
}

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

package main

import "fmt"

func main() {
    countryCapitalMap := map[string]string{"France": "Pairs", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}

    fmt.Println("原始地图")

    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap[country])
    }

    delete(countryCapitalMap, "France")
    fmt.Println("法国条目被删除")
    fmt.Println("删除元素后地图")

    for country := range countryCapitalMap {
        fmt.Println(country, "首都是", countryCapitalMap[country])
    }
}

Go语言递归函数

func recursion() {
    recursion()
}

Go语言接口

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

package main

type interface_name interface {
    method_name1 [return_type]
    method_name2 [return_type]
    method_name3 [return_type]
    method_namen [return_type]
}

type struct_name struct {

}

func (struct_name_variable struct_name) method_name1[return_type]() {

}
package main

import (
    "fmt"
)

type Phone interface {
    call()
}

type NokiaPhone struct {

}

func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {

}

func (iPhone IPhone) call() {
    fmt.Println("I an iPhone, I can call you!")
}

func main() {
    var phone Phone

    phone = new(NokiaPhone)
    phone.call()

    phone = new(IPhone)
    phone.call()
}

Go错误处理

Go语言通过内置的错误接口提供了非常简单的错误处理机制

//error类型是一个接口类型

type error interface {
    Error() string
}

可以在编码中通过实现error接口类型来生成错误信息

函数通常在最后的返回值中返回错误信息

package main

import (
    "fmt"

)

//定义一个DivideError结构
type DivideError struct {
    dividee int
    divider int
}

func (de *DivideError) Error() string {
    strFormat := `
        Cannot proceed, the divider is zero.
        dividee: %d
        divider:0`
    return fmt.Sprintf(strFormat, de.dividee)
}

func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
    if varDivider == 0 {
        dData := DivideError{
            dividee: varDividee,
            divider: varDivider,
        }
        errorMsg = dData.Error()
        return
    } else {
        return varDividee / varDivider, ""
    }
}

func main() {
    if result, errorMsg := Divide(100, 10) ; errorMsg == "" {
        fmt.Println("100/10 = ", result)
    }
    if _, errorMsg := Divide(100, 0); errorMsg != "" {
        fmt.Println("errorMsg is:", errorMsg)
    }
}

Go并发

Go语言支持并发,只需要通过go关键字来开启goroutine即可

goroutine是轻量级线程,goroutine的调度是由Golang运行时进行管理的

goroutine语法格式:

go 函数名(参数列表)

Go允许使用go语句开启一个新的运行期线程,即goroutine,以一个不同的、新创建的goroutine来执行一个函数。同一个程序中的所有goroutine共享同一个地址空间

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    //go f(x, y, z)  --> f(x, y, z)
    go say("world")
    say("hello")
}

 

通道channel

通道channel是用来传递数据的一个数据结构

通道可用于两个goroutine之间通过传递一个指定类型的值来同步运行和通讯。操作符<-用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道

ch <- v  //把v发送到通道ch
v := <-ch  //从ch接收数据并把值赋给v
//声明一个通道,使用chan关键字
ch := make(chan int)
//默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据
package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum  //把sum发送到通道c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c //从通道c中接收

    fmt.Println(x, y, x+y)
}
package main

//通道可以设置缓冲区,通过make的第二个参数指定缓冲区大小
//ch := make(chan int, 100)
//带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态
//如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值
//如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞

import "fmt"

func main() {
    ch := make(chan int, 2)

    ch <- 1
    ch <- 2

    fmt.Println(<- ch)
    fmt.Println(<- ch)

}
package main

//Go遍历通道与关闭通道
//Go通过range关键字来实现遍历读取到的数据,类似于与数组或切片  格式  v, ok := <-ch
//如果通道接收不到数据后ok就为false,这时通道就可以使用close()函数来关闭

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c)
    
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}

 

Go语言开发工具

Go基础

原文:https://www.cnblogs.com/liushoudong/p/12935793.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!