LOGO

Golang 入门-1.语法


特性

Go语言具有以下的特征:

  • 自动垃圾回收
  • 更丰富的内置类型
  • 函数多返回值
  • 错误处理
  • 匿名函数和闭包
  • 类型和接口
  • 并发编程
  • 反射
  • 语言交互性

命令

go build test.go # 生成可执行文件 test
go run test.go # 运行代码

关键字

25 个关键字

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

36 个预定义标识符

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

包引入

//包引入
package main

import (
	"fmt"
	"math"
	"strconv"
	"time"
	"unsafe"
)

全局声明

// 全局变量声明 var
var (
	goalA int
	goalB bool
)

// 全局常量声明 const
const (
	Unknown = iota
	Female
	Male
)

const (
	Tag     = "abc"
	TagLen  = len(Tag)
	TagSize = unsafe.Sizeof(Tag)
)

变量声明

//变量声明
func funcvar() {
	var m int = 2
	var n int = 2
	fmt.Println("res:", m+n)
}

打印和格式化

// 打印
func prt() {
	fmt.Println("Hello world")
}

// 打印全局, fmt格式化
func prtG() {
	fmt.Println(fmt.Sprintf("goal vars: goalA=%d, goalB=%v", goalA, goalB))
	fmt.Println(fmt.Sprintf("goal consts: Unknown=%d, Female=%d, Male=%d", Unknown, Female, Male))
	fmt.Println(fmt.Sprintf("goal consts: Tag=%s, TagLen=%d, TagSize=%d", Tag, TagLen, TagSize))
}

func funcfmt() {
var succ = true
var statuscode int = 200
var lon = 119.232322
var lat = 39.232322

// prec控制精度(排除指数部分):对'f'、'e'、'E',它表示小数点后的数字个数;对'g'、'G',它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
// bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。
strLon := strconv.FormatFloat(lon, 'f', -1, 32)
strLat := strconv.FormatFloat(lat, 'f', -1, 32)
var date = "2021-10-01"
var url = "succ=%t&code=%d&date=%s&lon=%s&lat=%s"
var targetUrl = fmt.Sprintf(url, succ, statuscode, date, strLon, strLat)
fmt.Println(targetUrl)
}

引用

// 引用
func funcref() {
	var n = 2
	// &var 获取地址, 引用类型
	// *m 指针, 获取地址m的表示的值
	m := &n
	var m2 *int = &n
	fmt.Println(n, m, m2)
	n = 4
	fmt.Println(n, m, m2, *m)
}

指针

// 指针
func funcptr() {
    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 )
    
    /* 空指针判断 */
    fmt.Println("ip == nil:", ip == nil)
    var  ptr *int
    fmt.Println("ptr == nil:", ptr == nil)
}

函数多返回值

//多返回值
func funnumbers() (int, float64, string) {
	a, b, c := 20, 64.2231, "ok"
	return a, b, c
}

// 多返回值调用
func funccallf() {
	_, f, s := funnumbers() // _ 忽略第一个返回值. _ 是一个只写变量,不能得到它的值
	fmt.Println(f, s)
}

iota使用

// iota使用
func funcconstiota() {
	const (
		a = iota //0
		b        //1
		c        //2
		d = "ha" //独立值,iota += 1
		e        //"ha"   iota += 1
		f = 100  //iota +=1
		g        //100  iota +=1
		h = iota //7,恢复计数
		i        //8
	)
    const (
        x = "hx"  	// hx
        y			// hx
    )
	const (
		i2 = 1 << iota // 1<<0
		j2 = 3 << iota // 3<<1
		k2             // 3<<2
		l2             // 3<<3
	)
	fmt.Println(a, b, c, d, e, f, g, h, i)
	fmt.Println(x, y)
	fmt.Println(i2, j2, k2, l2)
}

条件语句

// 条件语句 if switch select使用
func funccondition(i int) {
	if i < 0 {
		fmt.Println("if end", fmt.Sprintf("%d < 0", i))
	} else {
		fmt.Println("else end")
	}

	switch i {
	case 0:
		fmt.Println("case 0")
	case 1:
		fmt.Println("case 1")
	default:
		fmt.Println("case default")
	}
}

select使用

func fibonacci(c, quit chan int) {
	x, y := 1, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func funcselect() {
	c := make(chan int)
	quit := make(chan int)

	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()

	fibonacci(c, quit)
}

多函数参数

//多函数参数
func funcparams(name, nick string, age, work int) {
	fmt.Println(name, nick, age, work)

	/* 声明函数变量 */
	getSquareRoot := func(x float64) float64 {
		return math.Sqrt(x)
	}

	/* 使用函数 */
	fmt.Println(getSquareRoot(9))
}

闭包函数

//闭包函数
func getSequence() func() int {
	i:=0
	return func() int {
		i+=1
		return i
	}
}

//闭包函数使用
func funcclosepk() {
	nextNumber := getSequence()
	fmt.Println(nextNumber(), nextNumber(), nextNumber())
}

递归函数

func fibonacci3(n int) int {
	if n < 2 {
		return n
	}
	return fibonacci3(n-2) + fibonacci3(n-1)
}

func funcrecursion() {
	var i int
	for i = 0; i < 10; i++ {
		fmt.Printf("%d,", fibonacci3(i))
	}
	fmt.Print("\n")
}

结构体和方法

// Circle 结构体定义和方法定义
type Circle struct {
	radius float64
}
// 该 method 属于 Circle 类型对象中的方法
func (c Circle) getArea() float64 {
	return 3.14 * c.radius * c.radius
}

// c 需要使用指针 才能修改
func (c *Circle) setRadius(r float64) {
	c.radius = r
}

// 结构体的使用
func funcmethod() {
	var c Circle = Circle{2}
	fmt.Println(c.radius, "getArea", c.getArea())
	c.setRadius(3)
	fmt.Println(c.radius, "getArea", c.getArea())
}

数组的使用

//数组的使用
func funcarrays() {
	// 声明数组
	var l1 [5] int
	fmt.Println(l1)

	//初始化数组
	l2 := [3]int {2, 1, 3}
	//初始化不定长数组
	l3 := [...]int {2, 1, 3, 0}
	fmt.Println(l2)
	fmt.Println(l3)
	//将 1,3索引初始化
	l4 := [5]int {1: 1, 3: 9}
	fmt.Println(l4)

	l1[2] = 50
	fmt.Println(l1)

	ml1 := [2][3] int {}
	fmt.Println(ml1)
	ml2 := [2][3] int {{1,2,3}, {4,5,6}}
	fmt.Println(ml2)
	fmt.Println(ml2[1][2])
}

切片的使用

//切片的使用
func funcslice() {
	s1 := [] int{1,2,3,4,5,6,7,8}
	fmt.Println(s1[:3])
	fmt.Println(s1[1:3])
	fmt.Println(s1[1:])
	fmt.Println(cap(s1))
	//fmt.Println(s1 != nil)

}

map的使用

func funcmap() {
	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" ] /*如果确定是真实的,则存在,否则不存在 */
	/*fmt.Println(capital) */
	/*fmt.Println(ok) */
	if (ok) {
		fmt.Println("American 的首都是", capital)
	} else {
		fmt.Println("American 的首都不存在")
	}
}

range的使用

// range的使用
func funcrange() {
	nums := [] int{1,2,3,4,5,6,7,8}
	for i, num := range nums {
		fmt.Println(i, num)
	}

	for i, c := range "aBcd" {
		fmt.Println(i, c) // 输出的是字符  ascii码 97 66 99 100
	}

	kvs := map[string]string{"a": "apple", "b": "banana"}
	for k := range kvs {
		fmt.Printf("%s \n", k)
	}
	for k, v := range kvs {
		fmt.Printf("%s -> %s\n", k, v)
	}

	fmt.Println(kvs["a"])
}

接口的使用

// Phone 接口定义
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 am iPhone, I can call you!")
}

//接口的使用
func funcinterface() {
	var phone Phone

	phone = new(NokiaPhone)
	phone.call()

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

错误处理

func sqrt(f float64) (float64, error) {
	if f < 0 {
		return 0, errors.New("math: square root of negative number")
	}
	return math.Sqrt(f), nil
}

// 针对入参不应该有问题的函数,使用panic设计
func sqrtx(f float64) float64 {
	f2, err := sqrt(f)
	if(err != nil) {
		strF := strconv.FormatFloat(f, 'f', -1, 64)
		panic("error: sqrt(" + strF + "): " + err.Error())
	}
	return f2
}

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

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

// Divide 定义 `int` 类型除法运算的函数
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 funcerror() {

	v1, err1 := sqrt(64)
	fmt.Println("sqrt(64) = ", v1, err1)
	v2, err2 := sqrt(-64)
	fmt.Println("sqrt(-64) = ", v2, err2)
	v3 := sqrtx(64)
	fmt.Println("sqrtx(64) = ", v3)

	// 正常情况
	if result, errorMsg := Divide(100, 10); errorMsg == "" {
		fmt.Println("100/10 = ", result)
	}
	// 当除数为零的时候会返回错误信息
	if _, errorMsg := Divide(100, 0); errorMsg != "" {
		fmt.Println("errorMsg is: ", errorMsg)
	}
}

go并发

//定义耗时处理函数
func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

// go 并发
func funcgo() {
	go say("world") // goroutine(轻量级线程) 上运行
	say("hello")
}

chan 遍历

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

// channel 遍历的使用
func funcforchan() {
	c := make(chan int, 10)
	go fibonacci2(cap(c), c)
	// range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
	// 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
	// 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
	// 会结束,从而在接收第 11 个数据的时候就阻塞了。
	for i := range c {
		fmt.Println(i)
	}
}

调用 C库

/*
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import "unsafe"
// 导入虚拟包C必须单独一行,且跟在注释结束行后

func funccallc() {
    cstr := C.CString("Hello, world")
    C.puts(cstr)
    C.free(unsafe.Pointer(cstr))
}

文章作者: 鲁君树人
版权声明: 本篇文章采用 CC BY 4.0 版权协议『必须署名,可共享,可演绎』,转载请注明来源 幺蛾日记 !
评论
 上一篇
Golang 入门-0.特性 Golang 入门-0.特性
强类型静态编译型语言。 更丰富的内置类型 函数多返回值 在C中如果想返回多个值,通常会在调用函数中分配返回值的空间,并将返回值的指针传给被调函数。Go的做法是在传入的参数之上留了两个空位,被调者直接将返回值放在这两空位。Go是使用栈空间
2021-10-18
下一篇 
Golang 入门-2.并发 Golang 入门-2.并发
Goroutine(协程)Goroutine(协程, 不严谨) 是一种户态线程, 多个Goroutine中,Go使用通道(channel)进行通信。 进程:拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。线程:拥有自己独
2021-10-18
  目录