Golang基礎(chǔ)的示例分析

這篇文章將為大家詳細(xì)講解有關(guān)Golang基礎(chǔ)的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

成都網(wǎng)絡(luò)公司-成都網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)10余年經(jīng)驗成就非凡,專業(yè)從事做網(wǎng)站、網(wǎng)站設(shè)計,成都網(wǎng)頁設(shè)計,成都網(wǎng)頁制作,軟文發(fā)布平臺,1元廣告等。10余年來已成功提供全面的成都網(wǎng)站建設(shè)方案,打造行業(yè)特色的成都網(wǎng)站建設(shè)案例,建站熱線:13518219792,我們期待您的來電!

第一個golang程序

package main

import "fmt"

func main() {
	fmt.Println("hello golang")
}

基本數(shù)據(jù)類型

  1. 布爾型( true 或者 false)

  2. 數(shù)字類型( 整型 int 和 浮點型 float32、float64 )

  3. 字符串類型( 字符串就是一串固定長度的字符連接起來的字符序列 )

  4. 派生類型:

  • 指針類型(Pointer)

  • 數(shù)組類型

  • 結(jié)構(gòu)化類型(struct)

  • Channel 類型

  • 函數(shù)類型

  • 切片類型

  • 接口類型(interface)

  • Map 類型

數(shù)字類型

  1. 整形

  • uint8 無符號 8 位整型 (0 到 255)

  • uint16 無符號 16 位整型 (0 到 65535)

  • uint32 無符號 32 位整型 (0 到 4294967295)

  • uint64 無符號 64 位整型 (0 到 18446744073709551615)

  • int8 有符號 8 位整型 (-128 到 127)

  • int16 有符號 16 位整型 (-32768 到 32767)

  • int32 有符號 32 位整型 (-2147483648 到 2147483647)

  • int64 有符號 64 位整型 (-9223372036854775808 到 9223372036854775807)

  1. 浮點型

  • float32 32位浮點型數(shù)

  • float64 64位浮點型數(shù)

  • complex64 32 位實數(shù)和虛數(shù)

  • complex128 64 位實數(shù)和虛數(shù)

  1. 其他數(shù)字類型

  • byte 類似 uint8

  • rune 類似 int32

  • uint 32 或 64 位

  • int 與 uint 一樣大小

  • uintptr 無符號整型,用于存放一個指針

定義變量

// 聲明一個變量
var identifier type
// 可以一次聲明多個變量
var identifier1, identifier2 type
// 根據(jù)值自行判定變量類型
var v_name = value
// 簡短形式 省略 var, 注意 := 左側(cè)如果沒有聲明新的變量
v_name := value

定義常量

// 聲明一個常量
const identifier [type] = value
// 顯式類型定義
const b string = "abc"
// 隱式類型定義
const b = "abc"
// 多個相同類型的聲明(隱式類型定義)
const c_name1, c_name2 = value1, value2

iota

iota,特殊常量,可以認(rèn)為是一個可以被編譯器修改的常量

iota 在 const關(guān)鍵字出現(xiàn)時將被重置為 0(const 內(nèi)部的第一行之前),const 中每新增一行常量聲明將使 iota 計數(shù)一次(iota 可理解為 const 語句塊中的行索引)。

iota 可以被用作枚舉值

package main

import "fmt"

func main() {
	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,恢復(fù)計數(shù)
		i          //8
	)
	fmt.Println(a,b,c,d,e,f,g,h,i)
}

運行結(jié)果

0 1 2 ha ha 100 100 7 8

第一個 iota 等于 0,每當(dāng) iota 在新的一行被使用時,它的值都會自動加 1

條件控制語句

if & if else

package main

import "fmt"

func main() {
	var a = 12
	if a > 10 {
		fmt.Println("a>10")
	} else {
		fmt.Println("a<=10")
	}
}

運行結(jié)果

a>10

switch

package main

import "fmt"

func main() {
	var a = 12
	switch a {
	case 1:
		fmt.Println(1)
	case 2:
		fmt.Println(2)
	case 12:
		fmt.Println(12)
	default:
		fmt.Println(a)
	}
}

運行結(jié)果

12

使用 fallthrough 會強(qiáng)制執(zhí)行后面的 case 語句,fallthrough 不會判斷下一條 case 的表達(dá)式結(jié)果是否為 true

package main

import "fmt"

func main() {
	var a = 1
	switch a {
	case 1:
		fmt.Println(1)
		fallthrough
	case 2:
		fmt.Println(2)
	case 12:
		fmt.Println(12)
	default:
		fmt.Println(a)
	}
}

運行結(jié)果

1
2

select

select 是 Go 中的一個控制結(jié)構(gòu),類似于用于通信的 switch 語句。每個 case 必須是一個通信操作,要么是發(fā)送要么是接收。

select 隨機(jī)執(zhí)行一個可運行的 case。如果沒有 case 可運行,它將阻塞,直到有 case 可運行。一個默認(rèn)的子句應(yīng)該總是可運行的。

package main

import "fmt"

func main() {
	var c1, c2, c3 chan int
	var i1, i2 int
	select {
	case i1 = <-c1:
		fmt.Printf("received ", i1, " from c1\n")
	case c2 <- i2:
		fmt.Printf("sent ", i2, " to c2\n")
	case i3, ok := <-c3:
		if ok {
			fmt.Printf("received ", i3, " from c3\n")
		} else {
			fmt.Printf("c3 is closed\n")
		}
	default:
		fmt.Printf("no communication\n")
	}
}

運行結(jié)果

no communication

循環(huán)控制語句

for

package main

import "fmt"

func main() {
	for i := 1; i < 10; i++ {
		fmt.Println(i)
	}
}
package main

import "fmt"

func main() {
	var i = 1
	for i < 10 {
		fmt.Println(i)
		i++
	}
}

運行結(jié)果

1
2
3
4
5
6
7
8
9

死循環(huán)

for {

}

函數(shù)

package main

import "fmt"

func main() {
	test(1)
}
func test(i int) int {
	for i < 10 {
		fmt.Println(i)
		i++
	}
	return i
}

運行結(jié)果

1
2
3
4
5
6
7
8
9
package main

import "fmt"

func main() {
	i := test(1, 9)
	fmt.Println("最大值為:", i)
}
func test(i, j int) int {
	if i > j {
		return i
	} else {
		return j
	}
}

運行結(jié)果

最大值為: 9

函數(shù)返回多個值

package main

import "fmt"

func main() {
	s, s2 := test("hello", "go")
	fmt.Println(s, s2)
}
func test(i, j string) (string, string) {
	return i, j
}

運行結(jié)果

hello go

值傳遞 和 引用傳遞

package main

import "fmt"

func main() {
	var a = 3
	var b = 4
	fmt.Println("值傳遞運行前a=", a, "b=", b)
	test1(a, b)
	fmt.Println("值傳遞運行后a=", a, "b=", b)
	fmt.Println("===============================================")
	var i = 1
	var j = 2
	fmt.Println("引用傳遞運行前i=", i, "j=", j)
	test2(&i, &j)
	fmt.Println("引用傳遞運行后i=", i, "j=", j)
}

// 值傳遞
func test1(i, j int) (int, int) {
	var temp int
	temp = i
	i = j
	j = temp
	return i, j
}

// 引用傳遞
func test2(i, j *int) (int, int) {
	var temp int
	temp = *i
	*i = *j
	*j = temp
	return *i, *j
}

運行結(jié)果

值傳遞運行前a= 3 b= 4
值傳遞運行后a= 3 b= 4
===============================================
引用傳遞運行前i= 1 j= 2
引用傳遞運行后i= 2 j= 1

函數(shù)作為實參

package main

import "fmt"

func main() {
	funcA := func(a int) int {
		return a
	}
	fmt.Println(funcA(12))
}

運行結(jié)果

12

閉包

Go 語言支持匿名函數(shù),可作為閉包。匿名函數(shù)是一個"內(nèi)聯(lián)"語句或表達(dá)式。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內(nèi)的變量,不必申明。

package main

import "fmt"

func main() {
	next := getSequence()
	fmt.Println(next())
	fmt.Println(next())
	fmt.Println(next())
}

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

運行結(jié)果

2
3
4

方法

Go 語言中同時有函數(shù)和方法。一個方法就是一個包含了接受者的函數(shù),接受者可以是命名類型或者結(jié)構(gòu)體類型的一個值或者是一個指針。所有給定類型的方法屬于該類型的方法集

package main

import "fmt"

type Circle struct {
	radius float64
}

func (circle Circle) getPerimeter() float64 {
	return 3.14 * circle.radius * 2
}
func main() {
	var circle Circle
	circle.radius = 10
	fmt.Println(circle.getPerimeter())
}

運行結(jié)果

62.800000000000004

變量作用域

Go 語言中變量可以在三個地方聲明:

  • 函數(shù)內(nèi)定義的變量稱為局部變量

  • 函數(shù)外定義的變量稱為全局變量

  • 函數(shù)定義中的變量稱為形式參數(shù)

package main

import "fmt"

// 全局變量
var a = 1

func main() {
	// 局部變量
	var b = 2
	test(a)
	test(b)
}

// 形式參數(shù)
func test(a int) {
	fmt.Println(a)
}

數(shù)組

數(shù)組是具有相同唯一類型的一組已編號且長度固定的數(shù)據(jù)項序列,這種類型可以是任意的原始類型例如整形、字符串或者自定義類型

聲明數(shù)組

// 形式
var variable_name [SIZE] variable_type
// 舉例
var balance [10] float32

初始化數(shù)組

// 初始化一個長度為5的float32數(shù)組
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
// 如果忽略 [] 中的數(shù)字不設(shè)置數(shù)組大小
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance[6] = 60.0

訪問數(shù)組元素

var a float32 = balance[5]

指針

一個指針變量指向了一個值的內(nèi)存地址

聲明指針

// 形式
var var_name *var-type
// 舉例
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮點型 */
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)
}

運行結(jié)果

a 變量的地址是: c00000a0b0
ip 變量儲存的指針地址: c00000a0b0
*ip 變量的值: 20

空指針

當(dāng)一個指針被定義后沒有分配到任何變量時,它的值為 nil。

nil 指針也稱為空指針。一個指針變量通??s寫為 ptr。

package main

import "fmt"

func main() {
	var ip *int /* 聲明指針變量 */

	/* 指針變量的存儲地址 */
	fmt.Printf("ip 的值為: %x\n", ip)
}

運行結(jié)果

ip 的值為: 0

空指針判斷

if(ptr != nil)     /* ptr 不是空指針 */
if(ptr == nil)    /* ptr 是空指針 */

指針數(shù)組

package main

import "fmt"

func main() {
	a := []int{10, 100, 200}
	// 遍歷數(shù)組
	for i := 0; i < len(a); i++ {
		fmt.Printf("a[%d] = %d\n", i, a[i])
	}
	fmt.Println("==================================")
	// 有一種情況,我們可能需要保存數(shù)組,這樣我們就需要使用到指針。
	// 以下聲明了整型指針數(shù)組:
	var ptr [3]*int
	for i := 0; i < len(a); i++ {
		/* 整數(shù)地址賦值給指針數(shù)組 */
		ptr[i] = &a[i]
	}
	for i := 0; i < len(ptr); i++ {
		fmt.Printf("a[%d] = %d\n", i, *ptr[i])
	}
}

運行結(jié)果

a[0] = 10
a[1] = 100
a[2] = 200
==================================
a[0] = 10
a[1] = 100
a[2] = 200

指向指針的指針

如果一個指針變量存放的又是另一個指針變量的地址,則稱這個指針變量為指向指針的指針變量。 指向指針的指針變量聲明格式

var ptr **int;
package main

import "fmt"

func main() {
	var a int
	var ptr *int
	var pptr **int

	a = 3000

	/* 指針 ptr 地址 */
	ptr = &a

	/* 指向指針 ptr 地址 */
	pptr = &ptr

	/* 獲取 pptr 的值 */
	fmt.Printf("變量 a = %d\n", a)
	fmt.Printf("指針變量 *ptr = %d\n", *ptr)
	fmt.Printf("指向指針的指針變量 **pptr = %d\n", **pptr)
}

運行結(jié)果

變量 a = 3000
指針變量 *ptr = 3000
指向指針的指針變量 **pptr = 3000

指針作為函數(shù)參數(shù)

package main

import "fmt"

func main() {
	var a = 3
	var b = 4
	fmt.Println("值傳遞運行前a=", a, "b=", b)
	test1(a, b)
	fmt.Println("值傳遞運行后a=", a, "b=", b)
	fmt.Println("===============================================")
	var i = 1
	var j = 2
	fmt.Println("引用傳遞運行前i=", i, "j=", j)
	test2(&i, &j)
	fmt.Println("引用傳遞運行后i=", i, "j=", j)
}

// 值傳遞
func test1(i, j int) (int, int) {
	var temp int
	temp = i
	i = j
	j = temp
	return i, j
}

// 引用傳遞
func test2(i, j *int) (int, int) {
	var temp int
	temp = *i
	*i = *j
	*j = temp
	return *i, *j
}

運行結(jié)果

值傳遞運行前a= 3 b= 4
值傳遞運行后a= 3 b= 4
===============================================
引用傳遞運行前i= 1 j= 2
引用傳遞運行后i= 2 j= 1

結(jié)構(gòu)體

結(jié)構(gòu)體是由一系列具有相同類型或不同類型的數(shù)據(jù)構(gòu)成的數(shù)據(jù)集合。

結(jié)構(gòu)體表示一項記錄,比如保存圖書館的書籍記錄,每本書有以下屬性:

Title :標(biāo)題 Author : 作者 Subject:學(xué)科 ID:書籍ID

定義

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

一旦定義了結(jié)構(gòu)體類型,它就能用于變量的聲明,語法格式如下:

variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
package main

import "fmt"

// 一、定義結(jié)構(gòu)體
type Books struct {
	title   string
	author  string
	subject string
	book_id int
}

func main() {

	// 創(chuàng)建一個新的結(jié)構(gòu)體
	fmt.Println(Books{"Go 語言", "Google", "Go 語言教程", 6495407})

	// 也可以使用 key => value 格式
	fmt.Println(Books{title: "Go 語言", author: "Google", subject: "Go 語言教程", book_id: 6495407})

	// 忽略的字段為 0 或 空
	fmt.Println(Books{title: "Go 語言", author: "Google"})

	fmt.Println("=========================")

	// 二、訪問結(jié)構(gòu)體成員
	/* book 2 描述 */
	var Book2 Books
	Book2.title = "Python 教程"
	Book2.author = "Python"
	Book2.subject = "Python 語言教程"
	Book2.book_id = 6495700
	/* 打印 Book2 信息 */
	fmt.Printf("Book 2 title : %s\n", Book2.title)
	fmt.Printf("Book 2 author : %s\n", Book2.author)
	fmt.Printf("Book 2 subject : %s\n", Book2.subject)
	fmt.Printf("Book 2 book_id : %d\n", Book2.book_id)
	fmt.Println("=========================")
	// 三、結(jié)構(gòu)體作為函數(shù)參數(shù)
	printBook(Book2)
	fmt.Println("=========================")
	// 四、結(jié)構(gòu)體指針
	printBook2(&Book2)
}

func printBook(book Books) {
	fmt.Printf("Book title : %s\n", book.title)
	fmt.Printf("Book author : %s\n", book.author)
	fmt.Printf("Book subject : %s\n", book.subject)
	fmt.Printf("Book book_id : %d\n", book.book_id)
}

func printBook2(book *Books) {
	fmt.Printf("Book title : %s\n", book.title)
	fmt.Printf("Book author : %s\n", book.author)
	fmt.Printf("Book subject : %s\n", book.subject)
	fmt.Printf("Book book_id : %d\n", book.book_id)
}

運行結(jié)果

{Go 語言 Google Go 語言教程 6495407}
{Go 語言 Google Go 語言教程 6495407}
{Go 語言 Google  0}
=========================
Book 2 title : Python 教程
Book 2 author : Python
Book 2 subject : Python 語言教程
Book 2 book_id : 6495700
=========================
Book title : Python 教程
Book author : Python
Book subject : Python 語言教程
Book book_id : 6495700
=========================
Book title : Python 教程
Book author : Python
Book subject : Python 語言教程
Book book_id : 6495700

切片(Slice)

Go 數(shù)組的長度不可改變,與數(shù)組相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。

定義切片

  1. var identifier []type

  2. var slice1 []type = make([]type, len) 或者簡寫 slice1 := make([]type, len) 指定長度

  3. make([]T, length, capacity) 指定容量

package main

import "fmt"

func main() {
	// 切片初始化
	var slice = []int{1, 2, 3}
	// 從下標(biāo)startIndex到endIndex-1 下的元素 切片截取
	fmt.Println(slice[0:2])
	fmt.Println(slice[:2])
	fmt.Println(slice[0:])
	fmt.Println("=======================")
	// len() 和 cap() 函數(shù)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(slice), cap(slice), slice)
	fmt.Println("=======================")
	// 空切片
	var numbers []int

	fmt.Printf("len=%d cap=%d slice=%v\n", len(numbers), cap(numbers), numbers)

	if numbers == nil {
		fmt.Printf("切片是空的\n")
	}
	fmt.Println("=======================")
	// append() 和 copy() 函數(shù)
	var numbers1 []int
	// append() 追加
	numbers1 = append(numbers1, 1)
	numbers1 = append(numbers1, 2, 3, 4)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(numbers1), cap(numbers1), numbers1)
	fmt.Println("=======================")
	// copy() 復(fù)制
	/* 創(chuàng)建切片 numbers2 是之前切片的兩倍容量*/
	numbers2 := make([]int, len(numbers1), (cap(numbers1))*2)
	/* 拷貝 numbers1 的內(nèi)容到 numbers2 */
	copy(numbers2, numbers1)
	fmt.Printf("len=%d cap=%d slice=%v\n", len(numbers2), cap(numbers2), numbers2)
}

運行結(jié)果

[1 2]
[1 2]
[1 2 3]
=======================
len=3 cap=3 slice=[1 2 3]
=======================
len=0 cap=0 slice=[]
切片是空的
=======================
len=4 cap=4 slice=[1 2 3 4]
=======================
len=4 cap=8 slice=[1 2 3 4]

范圍(Range)

package main

import "fmt"

func main() {
	//這是我們使用range去求一個slice的和。使用數(shù)組跟這個很類似
	nums := []int{2, 3, 4}
	sum := 0
	for _, num := range nums {
		sum += num
	}
	fmt.Println("sum:", sum)
	//在數(shù)組上使用range將傳入index和值兩個變量。上面那個例子我們不需要使用該元素的序號,所以我們使用空白符"_"省略了。有時侯我們確實需要知道它的索引。
	for i, num := range nums {
		if num == 3 {
			fmt.Println("index:", i)
		}
	}
	//range也可以用在map的鍵值對上。
	kvs := map[string]string{"a": "apple", "b": "banana"}
	for k, v := range kvs {
		fmt.Printf("%s -> %s\n", k, v)
	}
	//range也可以用來枚舉Unicode字符串。第一個參數(shù)是字符的索引,第二個是字符(Unicode的值)本身。
	for i, c := range "go" {
		fmt.Println(i, c)
	}
}

運行結(jié)果

sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111

Map(集合)

Map 是一種無序的鍵值對的集合。Map 最重要的一點是通過 key 來快速檢索數(shù)據(jù),key 類似于索引,指向數(shù)據(jù)的值。

定義集合

/* 聲明變量,默認(rèn) map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函數(shù) */
map_variable := make(map[key_data_type]value_data_type)

如果不初始化 map,那么就會創(chuàng)建一個 nil map。nil map 不能用來存放鍵值對

package main

import "fmt"

func main() {
	var countryCapitalMap = make(map[string]string)

	/* map插入key - value對,各個國家對應(yīng)的首都 */
	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 的首都不存在")
	}

	fmt.Println("========================")
	// delete() 函數(shù)
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}
	// 刪除元素
	delete(countryCapitalMap, "France")
	fmt.Println("法國條目被刪除")
	for country := range countryCapitalMap {
		fmt.Println(country, "首都是", countryCapitalMap[country])
	}
}

運行結(jié)果

France 首都是 巴黎
Italy 首都是 羅馬
Japan 首都是 東京
India  首都是 新德里
American 的首都不存在
========================
India  首都是 新德里
France 首都是 巴黎
Italy 首都是 羅馬
Japan 首都是 東京
法國條目被刪除
Japan 首都是 東京
India  首都是 新德里
Italy 首都是 羅馬

遞歸函數(shù)

遞歸,就是在運行的過程中調(diào)用自己

階乘

package main

import "fmt"

func main() {
	var i int = 15
	fmt.Printf("%d 的階乘是 %d\n", i, Factorial(uint64(i)))
}

func Factorial(n uint64) (result uint64) {
	if n > 0 {
		result = n * Factorial(n-1)
		return result
	}
	return 1
}

運行結(jié)果

15 的階乘是 1307674368000

斐波那契數(shù)列

package main

import "fmt"

func main() {
	var i int
	for i = 0; i < 10; i++ {
		fmt.Printf("%d\t", fibonacci(i))
	}
}

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

運行結(jié)果

0	1	1	2	3	5	8	13	21	34

類型轉(zhuǎn)換

類型轉(zhuǎn)換用于將一種數(shù)據(jù)類型的變量轉(zhuǎn)換為另外一種類型的變量。

type_name(expression)
package main

import "fmt"

func main() {
	var sum int = 17
	var count int = 5
	var mean float32

	mean = float32(sum) / float32(count)
	fmt.Printf("mean 的值為: %f\n", mean)
}

運行結(jié)果

mean 的值為: 3.400000

接口

package main

import "fmt"

type Phone interface {
	call()
}

type NokiaPhone struct {
}
type IPhone struct {
}

func main() {
	n := new(NokiaPhone)
	n.call()
	i := new(IPhone)
	i.call()
}

func (NokiaPhone) call() {
	fmt.Println("nokiaPhone")
}

func (IPhone) call() {
	fmt.Println("IPhone")
}

運行結(jié)果

nokiaPhone
IPhone

錯誤處理

Go 語言通過內(nèi)置的錯誤接口提供了非常簡單的錯誤處理機(jī)制。

error類型是一個接口類型,這是它的定義

type error interface {
    Error() string
}

我們可以在編碼中通過實現(xiàn) error 接口類型來生成錯誤信息。

函數(shù)通常在最后的返回值中返回錯誤信息。使用errors.New 可返回一個錯誤信息

package main

import (
	"errors"
	"fmt"
)

func main() {
	_, err := Sqrt(-1)

	if err != nil {
		fmt.Println(err)
	}
}

func Sqrt(f float64) (float64, error) {
	if f < 0 {
		return 0, errors.New("math: square root of negative number")
	}
	// 實現(xiàn)
	return f, nil
}

運行結(jié)果

math: square root of negative number

并發(fā)

Go 語言支持并發(fā),我們只需要通過 go 關(guān)鍵字來開啟 goroutine 即可。

goroutine 是輕量級線程,goroutine 的調(diào)度是由 Golang 運行時進(jìn)行管理的。

goroutine 語法格式:

go 函數(shù)名( 參數(shù)列表 )

Go 允許使用 go 語句開啟一個新的運行期線程, 即 goroutine,以一個不同的、新創(chuàng)建的 goroutine 來執(zhí)行一個函數(shù)。 同一個程序中的所有 goroutine 共享同一個地址空間。

package main

import (
	"fmt"
	"time"
)

func main() {
	go say("world")
	say("hello")
}

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

運行結(jié)果

hello
world
world
hello
hello
world
world
hello
hello

通道(channel)

通道(channel)是用來傳遞數(shù)據(jù)的一個數(shù)據(jù)結(jié)構(gòu)。

通道可用于兩個 goroutine 之間通過傳遞一個指定類型的值來同步運行和通訊。操作符 <- 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。 聲明一個通道,通道在使用前必須先創(chuàng)建:

ch := make(chan int)

注意:默認(rèn)情況下,通道是不帶緩沖區(qū)的。發(fā)送端發(fā)送數(shù)據(jù),同時必須有接收端相應(yīng)的接收數(shù)據(jù)。

package main

import (
	"fmt"
)

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

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

運行結(jié)果

-5 17 12

通道緩沖區(qū)

通道可以設(shè)置緩沖區(qū),通過 make 的第二個參數(shù)指定緩沖區(qū)大小:

ch := make(chan int, 100)

帶緩沖區(qū)的通道允許發(fā)送端的數(shù)據(jù)發(fā)送和接收端的數(shù)據(jù)獲取處于異步狀態(tài),就是說發(fā)送端發(fā)送的數(shù)據(jù)可以放在緩沖區(qū)里面,可以等待接收端去獲取數(shù)據(jù),而不是立刻需要接收端去獲取數(shù)據(jù)。

不過由于緩沖區(qū)的大小是有限的,所以還是必須有接收端來接收數(shù)據(jù)的,否則緩沖區(qū)一滿,數(shù)據(jù)發(fā)送端就無法再發(fā)送數(shù)據(jù)了。

注意:如果通道不帶緩沖,發(fā)送方會阻塞直到接收方從通道中接收了值。如果通道帶緩沖,發(fā)送方則會阻塞直到發(fā)送的值被拷貝到緩沖區(qū)內(nèi);如果緩沖區(qū)已滿,則意味著需要等待直到某個接收方獲取到一個值。接收方在有值可以接收之前會一直阻塞。

package main

import (
	"fmt"
)

func main() {
	// 這里我們定義了一個可以存儲整數(shù)類型的帶緩沖通道
	// 緩沖區(qū)大小為2
	ch := make(chan int, 2)

	// 因為 ch 是帶緩沖的通道,我們可以同時發(fā)送兩個數(shù)據(jù)
	// 而不用立刻需要去同步讀取數(shù)據(jù)
	ch <- 1
	ch <- 2

	// 獲取這兩個數(shù)據(jù)
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

運行結(jié)果

1
2

遍歷通道與關(guān)閉通道

Go 通過 range 關(guān)鍵字來實現(xiàn)遍歷讀取到的數(shù)據(jù),類似于與數(shù)組或切片。格式如下:

v, ok := <-ch
package main

import (
	"fmt"
)

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	// range 函數(shù)遍歷每個從通道接收到的數(shù)據(jù),因為 c 在發(fā)送完 10 個
	// 數(shù)據(jù)之后就關(guān)閉了通道,所以這里我們 range 函數(shù)在接收到 10 個數(shù)據(jù)
	// 之后就結(jié)束了。如果上面的 c 通道不關(guān)閉,那么 range 函數(shù)就不
	// 會結(jié)束,從而在接收第 11 個數(shù)據(jù)的時候就阻塞了。
	for i := range c {
		fmt.Println(i)
	}
}

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	// 關(guān)閉通道
	close(c)
}

運行結(jié)果

0
1
1
2
3
5
8
13
21
34

關(guān)于“Golang基礎(chǔ)的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

名稱欄目:Golang基礎(chǔ)的示例分析
分享地址:http://muchs.cn/article28/iegpjp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、App開發(fā)、做網(wǎng)站網(wǎng)站設(shè)計、網(wǎng)站排名用戶體驗

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計