var num int// 0 var str string// "" var b bool// false
以下的值,都设为nil,类似于C/C++中的NULL
1 2 3 4 5 6
var a *int var a []int var a map[string] int var a chanint var a func(string)int var a error// error 是接口
方法二:自动判断类型
1
varnum = 1
方法三:省略var
使用:=,这是一个声明语句(左侧如果没有声明新的变量,就产生编译错误)
1 2 3
varnumint = 1 //相等于 num := 1
格式化输出字符串
使用Printf
1
fmt.Printf("%d,%s",666,"Wuhlan")
使用Sprintf和Println
1 2 3 4 5 6 7 8 9 10 11
var str = "%d,%s" var num int = 666 var name string = "Wuhlan" str = fmt.Sprintf(str,num,name) fmt.Println(str) /******************************************/ //也可以这样写 var num int = 666 var name string = "Wuhlan" str := fmt.Sprintf("%d,%s", num, name) fmt.Println(str)
数据类型
类型和描述
1
布尔型
布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool =
true。
2
数字类型 整型 int
和浮点型 float32、float64等,Go
语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
/* *2. init 函数会检查长和宽是否大于0 */ func init(){ println("main package initialized") if rectLen < 0 { log.Fatal("length is less than zero") } if rectWidth < 0 { log.Fatal("width is less than zero") } }
func main(){ fmt.Println("Geometrical shape properties") fmt.Printf("area of rectangle %.2f\n", rectangle.Area(rectLen, rectWidth)) fmt.Printf("diagonal of the rectangle %.2f ", rectangle.Diagonal(rectLen, rectWidth)) }
如果将rectLen将改为-6。则会有日志报错:
1 2 3 4
PS E:\go\src> go run geometry main package initialized 2021/10/0914:28:40 length is less than zero exit status 1
s := int {1,2,3} //直接初始化切片,[]是切片类型 s := arr[:] //对arr的引用 s := arr[startIndex:endIndex] //将 arr 中从下标 startIndex 到 endIndex-1 创建一个新的切片。 s := arr[startIndex:] s := arr[:endIndex] s1 := s[startIndex:endIndex] //切片初始化为s1 s :=make([]int,len,cap)
funcmain() { e := Employee{ name: "Mark Andrew", age: 50, } fmt.Printf("Employee name before change: %s", e.name) e.changeName("Michael Andrew") fmt.Printf("\nEmployee name after change: %s", e.name)
fmt.Printf("\n\nEmployee age before change: %d", e.age) e.changeAge(51) fmt.Printf("\nEmployee age after change: %d", e.age) }
输出:
1 2 3 4 5
Employee name beforechange: Mark Andrew Employee name afterchange: Mark Andrew
Employee age beforechange: 50 Employee age afterchange: 51
package main import"fmt" funcproducer(chnl chanint) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) } funcmain() { ch := make(chanint) go producer(ch) for { v, ok := <-ch if ok == false { break } fmt.Println("Received ", v, ok) } }
使用for range遍历
使用for
range,会自动判断信道是否已经关闭,若已经关闭,则会自动结束循环
上述代码可以修改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
package main
import"fmt" funcproducer(chnl chanint) { for i := 0; i < 10; i++ { chnl <- i } close(chnl) } funcmain() { ch := make(chanint) go producer(ch) for v := range ch { fmt.Println("Received ",v) } }
type Job struct { id int randomno int } type Result struct { job Job sumofdigits int }
var jobs = make(chan Job, 10) var results = make(chan Result, 10) //对一个数字的每位数求和 funcdigits(number int)int { sum := 0 no := number for no != 0 { digit := no % 10 sum += digit no /= 10 } time.Sleep(2 * time.Second) return sum } //调用digits函数,将结构体输入到results信道中,并且waitGroup的计数器减一 funcworker(wg *sync.WaitGroup) { for job := range jobs { output := Result{job, digits(job.randomno)} results <- output } wg.Done() } //创建工作池,调用worker函数(进行计算并输出),当所有go程都运行结束后才停止 funccreateWorkerPool(noOfWorkers int) { var wg sync.WaitGroup for i := 0; i < noOfWorkers; i++ { wg.Add(1) go worker(&wg) } wg.Wait() close(results) } //初始化,生成随机数并且输入到jobs信道中 funcallocate(noOfJobs int) { for i := 0; i < noOfJobs; i++ { randomno := rand.Intn(999) job := Job{i, randomno} jobs <- job } close(jobs)//关闭信道,告诉接收方不再有数据发来 } //输出结果,当全部输出完成后,done信道才会接收true信息,主go程<-done才能运行。这是用来避免过早地结束主程序。 funcresult(done chanbool) { for result := range results { fmt.Printf("Job id %d, input random no %d , sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits) } done <- true } funcmain() { startTime := time.Now() noOfJobs := 20 go allocate(noOfJobs) done := make(chanbool) go result(done) noOfWorkers := 10 createWorkerPool(noOfWorkers) //go result(done)也可以放在这里,没有影响 <-done endTime := time.Now() diff := endTime.Sub(startTime) fmt.Println("total time taken ", diff.Seconds(), "seconds") }
Job id 3, input random no 983 , sum of digits 20 Job id 1, input random no 636 , sum of digits 15 Job id 7, input random no 998 , sum of digits 26 Job id 0, input random no 878 , sum of digits 23 Job id 5, input random no 735 , sum of digits 15 Job id 2, input random no 407 , sum of digits 11 Job id 9, input random no 150 , sum of digits 6 Job id 8, input random no 904 , sum of digits 13 Job id 6, input random no 520 , sum of digits 7 Job id 4, input random no 895 , sum of digits 22 Job id 19, input random no 914 , sum of digits 14 Job id 10, input random no 212 , sum of digits 5 Job id 17, input random no 506 , sum of digits 11 Job id 11, input random no 538 , sum of digits 16 Job id 12, input random no 750 , sum of digits 12 Job id 16, input random no 630 , sum of digits 9 Job id 15, input random no 215 , sum of digits 8 Job id 18, input random no 20 , sum of digits 2 Job id 13, input random no 362 , sum of digits 11 Job id 14, input random no 436 , sum of digits 13 total time taken 4.0083858 seconds
import ( "fmt" "sync" ) var x = 0 funcincrement(wg *sync.WaitGroup){ x++ wg.Done() } funcmain(){ var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println(x) }
输出:
1
982/984/992
使用mutex解决临界区问题
外部定义互斥锁var m sync.Mutex
1 2 3
m.Lock() x++ m.Unlock()
输出:
1
1000
使用信道解决临界区问题
1 2 3
ch <- true x++ <- ch
输出:
1
1000
关于互斥锁和信道的选择问题。
当 Go
协程需要与其他协程通信时,可以使用信道。而当只允许一个协程访问临界区时,可以使用
Mutex。