golang基礎之一

1、第一個go程序

package main

import (
       "fmt"
)

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

對於代碼的解釋html

若是是爲了將代碼編譯成一個可執行程序,那麼package必須是main
若是是爲了將代碼編譯成庫,那麼package則沒有限制
go中全部的代碼都應該隸屬一個包python

fmt 是go的一個系統庫linux

fmt.println()則能夠打印輸出golang

若是想要運行程序:go run 程序名併發

在一個可執行程序只有一個main函數函數

關於註釋高併發

單行註釋://
多行註釋:/* */單元測試

2、go語言初識

關於定義一個變量測試

var 變量名 變量類型
變量名 = 值ui

這裏須要注意:go語言中定義的變量必須被用到,不然會報錯
同時定義變量和賦值能夠一步完成經過: 變量名 := 值

定義一個函數

若是咱們要定義一個函數,咱們先看下面求和的例子:

func add(a int,b int) int {
    var sum int
    sum = a + b
    return sum
}

這裏咱們須要知道,下面這種格式是被嚴格要求的,包括第一行的大括號不能放到下一行
func 函數名(參數1 參數1類型,參數2 參數2類型) 返回值類型 { 

}

3、golang語言特性

垃圾回收

內存自動回收,不須要開發人員管理內存
開發人員專一業務實現
只須要new分配內存,不須要釋放

自然高併發

  • 從語言曾元支持併發,很是簡單
  • goroute,輕量級線程,建立成千上萬goroute成爲可能
  • 基於CSP模型實現

關於高併發的一個簡單演示:

import (
    "fmt"
    "time"
)


func test_print(a int){
    fmt.Println(a)
}


func main(){
    for i:= 0;i < 100; i ++ {
        go test_print(i)
    }
    time.Sleep(time.Second)
}

在實現高併發的時候只須要在調用的函數前面加上go,就表示開啓了併發

若是在for循環的外面不加上time.Sleep(time.Second),就會發現會少打印了,這是由於當主程序運行完以後,並不會等待線程,因此程序直接終止

channel管道

相似linux中的pipe
多個goroute之間經過channel進行通訊
支持任何類型

package main

import (
    "fmt"
)

func test_pipe(){
    pipe := make(chan int,3)
    pipe <- 1
    pipe <- 2
    pipe <- 3

    fmt.Println(len(pipe))
}

func main(){
    test_pipe()
}

上述代碼的解釋:
pipe := make(chan int,3) 這裏是定義一個管道pipe,go是強類型語言,因此這裏聲明一個管道變量pipe須要經過有三個參數,chan表示是管道,int表示管道類型,3表示管道容量
經過len(pipe)能夠查看管道的的長度

若是想要從管道里獲取數據
t1 :=<- pipe 這個寫法等同於
var t1 int
t1 = <- pipe
fmt.Println(t1)
管道遵循的原則是先進先出,因此第一個獲取的值是1

小結:若是想要給管道放入值:定義的管道pipe < - 要存入的內容
若是想要從管道中獲取值:變量名 =<- 定義的管道pipe

這裏強調一下go中package包的概念,一個包裏的變量,在這個包裏是均可以訪問,可是在包以外也是有權限限制是否能夠訪問到,若是一個變量在一個包裏是大寫的,在其餘包裏就能夠訪問到,若是是小寫的其餘包裏則訪問不到。相似其餘語言中的public和private

多返回值

一個函數能夠返回多個值

package main

import "fmt"

func calc(a int,b int) (int,int ){
    sum := a + b
    avg := sum / 2
    return sum,avg
}

func main(){
    sum,avg := calc(100,200)
    fmt.Println(sum,avg)
}

關於須要傳入多個參數的時候是用括號括起來單個的狀況下通常不用括號括起來,直接int,而這裏是返回兩個則須要 (int,int)表示返回兩個整數類型值

若是有多個返回值,可是我只想返回一個值,是經過下劃線方式實現,則上述代碼改成:

func main(){
    sum,_ := calc(100,200)
    fmt.Println(sum)
}

4、包的概念

  • 和python同樣,把相同功能的代碼放到一個目錄,稱之爲包
  • 包能夠被其餘包引用
  • main包是用來生成可執行文件,每一個程序只有一個main包
  • 包的主要用途是提升代碼的可複用性

關於main包中的main函數,go程序通過編譯以後,運行該程序,會將編譯好的二進制文件加載到內存中,會首先調用main函數,因此main函數是程序的入口函數,即必須有package main

關於包,是咱們能夠把一些經常使用的功能封裝到包中,這個時候包中的每一個go文件的開頭則不須要package main,而是package 自定義名字,這個自定義名字是根據這個包的功能進行命名

go源碼按package進行組織,而且package要放到非註釋的第一行
一個程序只有一個main包,一個包中只能有一個main函數,不能重複定義
main函數是程序的執行入口
沒有被引用的變量,編譯的時候會報錯

 

go的目錄規範

這裏舉一個簡單的例子:若是咱們在創建一個go_project目錄,一般在這個目錄下咱們會建立以下目錄
src 存放不一樣的項目代碼
bin 存放編譯後的可執行程序
vender 存放引用的第三方庫
pgk 存放靜態庫

 

咱們的go環境變量中的GOPATH通常會設置爲:
(我這裏是路徑是/Users/myname/learngo)
export GOPATH=/Users/myname/learngo

go的編譯

若是咱們寫好了go的代碼文件,咱們若是測試運行能夠經過:
go run 快速執行go文件
go build 編譯程序,生成二進制文件
go install 安裝可執行文件到bin目錄下

基本命令:
go test執行單元測試或壓力測試
go env 顯示go相關的環境變量
go fmt 格式化源代碼

咱們經過下面例子理解這個編譯命令的使用:

例子一

我在/Users/myname/learng/src/go_dev/day01/hello目錄下寫了一個hello程序
如今把這個hello程序進行編譯

咱們在go_project目錄下執行的編譯命令,若是不指定編譯生成的文件會直接將編譯文件生成在當前目錄即go_project目錄下

這裏須要解釋的是go build 後面的路徑go build go_dev/day01/hello 
咱們從目錄結構能夠看出,go_dev的上一級目錄src目錄並無寫,這是由於go編譯的時候,會自動去GOPATH下的src目錄裏去找,因此這裏是不須要寫,同時編譯的路徑的最後咱們只寫到hello目錄而不是hello.go文件

例子二

咱們在/users/myname/go_project/src/go_dev/day01/ 目錄下創建一個goroute目錄
並在goroute目錄下創建兩個go文件,main.go和goroute.go文件

main.go文件的代碼爲:

package main
import (
       "time"
)

func main(){
        for i := 0; i < 100; i++ {
            go test_goroute(i)
        }
        time.Sleep(time.Second)
}

goroute.go文件的代碼爲:

package main

import "fmt"

func test_goroute(a int){
    fmt.Println(a)
}

這樣咱們編譯的時候只須要在go_project目錄下執行:
go build go_dev/day01/goroute
這樣就會再go_project目錄下生成一個可執行文件goroute

例子3
仍是在/users/myname/go_project/src/go_dev/day01/下創建一個goroute_test目錄
在goroute_test目錄下創建calc目錄和main目錄
同時在calc下創建一個sum.go文件,在main目錄下創建一個main.go文件

sum.go文件代碼以下:

package calc


func Add(a int,b int,c chan int){
    sum := a + b
    c <- sum
}

這裏有個地方須要注意這裏咱們的sum.go是做爲包寫的,因此咱們開頭是:package calc,即package+sum.go的所在上級目錄,而且是sum中定義的函數名首字母要大些(這個是必須的)這裏實際上是由於
咱們定義的包都是要被外部的其餘包調用,即咱們這裏定義的sum.go是要被其餘包調用,這個時候只有首字母大寫才能被其餘包調用到

main.go文件代碼以下:

package main

import (
    "fmt"
    "go_dev/day01/goroute_test/calc"
)

func main(){
    pipe := make(chan int,1)
    calc.Add(100,200,pipe)
    res :=<- pipe
    fmt.Println(res)
}

此次咱們編譯的時候指定編譯文件生成的目錄路徑,命令以下:
go build -o bin/goroute_test go_dev/day01/goroute_test/main

 

關於單元測試例子:
單元測試的代碼文件的名字格式必須是:*_test.go
例如我要寫關於calc.go文件的單元測試
新建一個文件命名爲:calc_test.go

這裏須要知道的是開頭的calc的名字並非強制的,可是爲了方便測試哪一個代碼文件,開頭就以那個文件開頭,下面是一個例子代碼:

 1 package calc
 2 
 3 import (
 4     "testing"
 5 )
 6 func TestAdd(t *testing.T){
 7     var sum int
 8     sum = Add(5,6)
 9     if sum != 11{
10         t.Fatalf("add is not right,sum:%v expected:11",sum)
11     }
12     t.Logf("add is Ok")
13 }

在代碼中咱們定義函數時候函數的名字也須要以Test開頭
上述測試文件執行結果:

 1 bogon:calc myname$ go test
 2 PASS
 3 ok      go_dev/01/calc  0.007s
 4 bogon:calc myname$ go test -v
 5 === RUN   TestAdd
 6 --- PASS: TestAdd (0.00s)
 7     calc_test.go:12: add is Ok
 8 PASS
 9 ok      go_dev/01/calc  0.007s
10 bogon:calc myname$

Go的結構開發規範 

好的代碼規範是很是重要的,這樣當你看別人代碼或者別人看你的代碼的時候就能很清楚的明白,下面是結構規範

// 當前程序的包名
package main

//導入其餘的包
import "fmt"

//常量的定義
const PI=3.14

//全局變量的聲明和賦值
var name = "gopher"

//通常類型聲明
type newType int

//結構的聲明
type gopher struct{}

//接口的聲明
type golang interface{}

//由main函數做爲程序入口點啓動
func main(){
    fmt.Println("Hello world! 你好世界")
}

 轉自https://www.cnblogs.com/zhaof/p/6962813.html

相關文章
相關標籤/搜索