亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

go語言基礎語法示例

2020-04-01 19:01:34
字體:
來源:轉載
供稿:網友

周末天氣不好,只能宅在家里,于是就順便看了一下Go語言,覺得比較有意思,所以寫篇文章介紹一下。我想寫一篇你可以在乘坐地鐵或公交車上下班時就可以初步了解一門語言的文章。所以,下面的文章主要是以代碼和注釋為主。只需要你對Java,Python,C等編程語言有一點基礎,我相信你會在30分鐘左右讀完并對Go語言有一些初步了解的。

本文的唯一目的,就是希望大家閱讀之后,能夠了解golang/72658.html">go語言長什么樣子。。。

go語言,基本語法,go,的基礎語法,語言語法

Hello World

package main //聲明本文件的package名 import "fmt" //import語言的fmt庫——用于輸出 func main() {   fmt.Println("hello world") }

運行

你可以有兩種運行方式,

解釋執行(實際是編譯成a.out再執行. $go run hello.go hello world編譯執行  $go build hello.go $ls hello hello.go $./hello hello world

自己的package

你可以使用GOPATH環境變量,或是使用相對路徑來import你自己的package。

Go的規約是這樣的:

1)在import中,你可以使用相對路徑,如 ./或 ../ 來引用你的package

2)如果沒有使用相對路徑,那么,go會去找$GOPATH/src/目錄。

使用相對路徑

import "./haoel" //import當前目錄里haoel子目錄里的所有的go文件

使用GOPATH路徑

import "haoel" //import 環境變量 $GOPATH/src/haoel子目錄里的所有的go文件

fmt輸出格式

fmt包和libc里的那堆使用printf, scanf,fprintf,fscanf 很相似。下面的東西對于C程序員不會陌生。

注意:Println不支持,Printf才支持%式的輸出:

package main import "fmt"import "math" func main() {  fmt.Println("hello world")   fmt.Printf("%t/n", 1==2)  fmt.Printf("二進制:%b/n", 255)  fmt.Printf("八進制:%o/n", 255)  fmt.Printf("十六進制:%X/n", 255)  fmt.Printf("十進制:%d/n", 255)  fmt.Printf("浮點數:%f/n", math.Pi)  fmt.Printf("字符串:%s/n", "hello world")}

當然,也可以使用如/n/t/r這樣的和C語言一樣的控制字符

變量和常量

變量的聲明很像 javascript,使用 var關鍵字。注意:go是靜態類型的語言,下面是代碼:

//聲明初始化一個變量var x int = 100var str string = "hello world"</pre>//聲明初始化多個變量var i, j, k int = 1, 2, 3 //不用指明類型,通過初始化值來推導var b = true //bool型

還有一種定義變量的方式(這讓我想到了Pascal語言,但完全不一樣)

x := 100 //等價于 var x int = 100;

常量很簡單,使用const關鍵字:

const s string = "hello world" const pi float32 = 3.1415926

數組

直接看代碼(注意其中的for語句,和C很相似吧,就是沒有括號了)

func main() {  var a [5]int  fmt.Println("array a:", a)   a[1] = 10  a[3] = 30  fmt.Println("assign:", a)   fmt.Println("len:", len(a))   b := [5]int{1, 2, 3, 4, 5}  fmt.Println("init:", b)   var c [2][3]int  for i := 0; i < 2; i++ {    for j := 0; j < 3; j++ {      c[i][j] = i + j    }  }  fmt.Println("2d: ", c)}

運行結果:

array a: [0 0 0 0 0]
assign: [0 10 0 30 0]
len: 5
init: [1 2 3 4 5]
2d: [[0 1 2] [1 2 3]]

數組的切片操作

這個很Python了。

a := [5]int{1, 2, 3, 4, 5}b := a[2:4] // a[2] 和 a[3],但不包括a[4]fmt.Println(b)b = a[:4] // 從 a[0]到a[4],但不包括a[4]fmt.Println(b)b = a[2:] // 從 a[2]到a[4],且包括a[2]fmt.Println(b)

分支循環語句

if語句

注意:if 語句沒有圓括號,而必需要有花括號

//if 語句if x % 2 == 0 {  //...}//if - elseif x % 2 == 0 {  //偶數...} else {  //奇數...} //多分支if num < 0 {  //負數} else if num == 10 {  //零} else {  //正數}

switch 語句

注意:switch語句沒有break,還可以使用逗號case多個值

switch i {  case 1:    fmt.Println("one")  case 2:    fmt.Println("two")  case 3:    fmt.Println("three")  case 4,5,6:    fmt.Println("four, five, six")  default:    fmt.Println("invalid value!")}

for 語句

前面你已見過了,下面再來看看for的三種形式:(注意:Go語言中沒有while)

//經典的for語句 init; condition; postfor i := 0; i<10; i++{   fmt.Println(i)} //精簡的for語句 conditioni := 1for i<10 {  fmt.Println(i)  i++} //死循環的for語句 相當于for(;;)i :=1for {  if i>10 {    break  }  i++}

關于分號

從上面的代碼我們可以看到代碼里沒有分號。其實,和C一樣,Go的正式的語法使用分號來終止語句。和C不同的是,這些分號由詞法分析器在掃描源代碼過程中使用簡單的規則自動插入分號,因此輸入源代碼多數時候就不需要分號了。

規則是這樣的:如果在一個新行前方的最后一個標記是一個標識符(包括像int和float64這樣的單詞)、一個基本的如數值這樣的文字、或以下標記中的一個時,會自動插入分號:

break continue fallthrough return ++ -- ) }
通常Go程序僅在for循環語句中使用分號,以此來分開初始化器、條件和增量單元。如果你在一行中寫多個語句,也需要用分號分開。

注意:無論任何時候,你都不應該將一個控制結構((if、for、switch或select)的左大括號放在下一行。如果這樣做,將會在大括號的前方插入一個分號,這可能導致出現不想要的結果。

map

map在別的語言里可能叫哈希表或叫dict,下面是和map的相關操作的代碼,代碼很容易懂

func main(){  m := make(map[string]int) //使用make創建一個空的map   m["one"] = 1  m["two"] = 2  m["three"] = 3   fmt.Println(m) //輸出 map[three:3 two:2 one:1] (順序在運行時可能不一樣)  fmt.Println(len(m)) //輸出 3   v := m["two"] //從map里取值  fmt.Println(v) // 輸出 2   delete(m, "two")  fmt.Println(m) //輸出 map[three:3 one:1]   m1 := map[string]int{"one": 1, "two": 2, "three": 3}  fmt.Println(m1) //輸出 map[two:2 three:3 one:1] (順序在運行時可能不一樣)   for key, val := range m1{    fmt.Printf("%s => %d /n", key, val)    /*輸出:(順序在運行時可能不一樣)      three => 3      one => 1      two => 2*/  }}

指針

Go語言一樣有指針,看代碼

var i int = 1var pInt *int = &i//輸出:i=1   pInt=0xf8400371b0    *pInt=1fmt.Printf("i=%d/tpInt=%p/t*pInt=%d/n", i, pInt, *pInt) *pInt = 2//輸出:i=2   pInt=0xf8400371b0    *pInt=2fmt.Printf("i=%d/tpInt=%p/t*pInt=%d/n", i, pInt, *pInt) i = 3//輸出:i=3   pInt=0xf8400371b0    *pInt=3fmt.Printf("i=%d/tpInt=%p/t*pInt=%d/n", i, pInt, *pInt)

Go具有兩個分配內存的機制,分別是內建的函數new和make。他們所做的事不同,所應用到的類型也不同,這可能引起混淆,但規則卻很簡單。

內存分配

new 是一個分配內存的內建函數,但不同于其他語言中同名的new所作的工作,它只是將內存清零,而不是初始化內存。new(T)為一個類型為T的新項目分配了值為零的存儲空間并返回其地址,也就是一個類型為*T的值。用Go的術語來說,就是它返回了一個指向新分配的類型為T的零值的指針。

make(T, args)函數的目的與new(T)不同。它僅用于創建切片、map和chan(消息管道),并返回類型T(不是*T)的一個被初始化了的(不是零)實例。這種差別的出現是由于這三種類型實質上是對在使用前必須進行初始化的數據結構的引用。例如,切片是一個具有三項內容的描述符,包括指向數據(在一個數組內部)的指針、長度以及容量,在這三項內容被初始化之前,切片值為nil。對于切片、映射和信道,make初始化了其內部的數據結構并準備了將要使用的值。如:

下面的代碼分配了一個整型數組,長度為10,容量為100,并返回前10個數組的切片

make([]int, 10, 100)
以下示例說明了new和make的不同。

var p *[]int = new([]int)  // 為切片結構分配內存;*p == nil;很少使用var v []int = make([]int, 10) // 切片v現在是對一個新的有10個整數的數組的引用 // 不必要地使問題復雜化:var p *[]int = new([]int)fmt.Println(p) //輸出:&[]*p = make([]int, 10, 10)fmt.Println(p) //輸出:&[0 0 0 0 0 0 0 0 0 0]fmt.Println((*p)[2]) //輸出: 0 // 習慣用法:v := make([]int, 10)fmt.Println(v) //輸出:[0 0 0 0 0 0 0 0 0 0]

函數

老實說,我對Go語言這種反過來聲明變量類型和函數返回值的做法有點不滿(保持和C一樣的不可以嗎? 呵呵)

package mainimport "fmt" func max(a int, b int) int { //注意參數和返回值是怎么聲明的   if a > b {    return a  }  return b} func main(){  fmt.Println(max(4, 5))}

函數返回多個值

Go中很多Package 都會返回兩個值,一個是正常值,一個是錯誤,如下所示:

package mainimport "fmt" func main(){  v, e := multi_ret("one")  fmt.Println(v,e) //輸出 1 true   v, e = multi_ret("four")  fmt.Println(v,e) //輸出 0 false   //通常的用法(注意分號后有e)  if v, e = multi_ret("four"); e {    // 正常返回  }else{    // 出錯返回  }} func multi_ret(key string) (int, bool){  m := map[string]int{"one": 1, "two": 2, "three": 3}   var err bool  var val int   val, err = m[key]   return val, err}

函數不定參數

例子很清楚了,我就不多說了

func sum(nums ...int) {  fmt.Print(nums, " ") //輸出如 [1, 2, 3] 之類的數組  total := 0  for _, num := range nums { //要的是值而不是下標    total += num  }  fmt.Println(total)}func main() {  sum(1, 2)  sum(1, 2, 3)   //傳數組  nums := []int{1, 2, 3, 4}  sum(nums...)}

函數閉包

nextNum這個函數返回了一個匿名函數,這個匿名函數記住了nextNum中i+j的值,并改變了i,j的值,于是形成了一個閉包的用法

func nextNum() func() int {  i,j := 1,1  return func() int {    var tmp = i+j    i, j = j, tmp    return tmp  }}//main函數中是對nextNum的調用,其主要是打出下一個斐波拉契數func main(){  nextNumFunc := nextNum()  for i:=0; i<10; i++ {    fmt.Println(nextNumFunc())  }}

函數的遞歸

和c基本是一樣的

func fact(n int) int {  if n == 0 {    return 1  }  return n * fact(n-1)} func main() {  fmt.Println(fact(7))}

結構體

Go的結構體和C的基本上一樣,不過在初始化時有些不一樣,Go支持帶名字的初始化。

type Person struct {  name string  age int  email string} func main() {  //初始化  person := Person{"Tom", 30, "tom@gmail.com"}  person = Person{name:"Tom", age: 30, email:"tom@gmail.com"}   fmt.Println(person) //輸出 {Tom 30 tom@gmail.com}   pPerson := &person   fmt.Println(pPerson) //輸出 &{Tom 30 tom@gmail.com}   pPerson.age = 40  person.name = "Jerry"  fmt.Println(person) //輸出 {Jerry 40 tom@gmail.com}}

結構體方法

不多說了,看代碼吧。

注意:Go語言中沒有public, protected, private的關鍵字,所以,如果你想讓一個方法可以被別的包訪問的話,你需要把這個方法的第一個字母大寫。這是一種約定。

type rect struct {  width, height int} func (r *rect) area() int { //求面積  return r.width * r.height} func (r *rect) perimeter() int{ //求周長  return 2*(r.width + r.height)} func main() {  r := rect{width: 10, height: 15}   fmt.Println("面積: ", r.area())  fmt.Println("周長: ", r.perimeter())   rp := &r  fmt.Println("面積: ", rp.area())  fmt.Println("周長: ", rp.perimeter())}

接口和多態

接口意味著多態,下面是一個經典的例子,不用多說了,自己看代碼吧。

//---------- 接 口 --------//type shape interface {  area() float64 //計算面積  perimeter() float64 //計算周長} //--------- 長方形 ----------//type rect struct {  width, height float64} func (r *rect) area() float64 { //面積  return r.width * r.height} func (r *rect) perimeter() float64 { //周長  return 2*(r.width + r.height)} //----------- 圓 形 ----------//type circle struct {  radius float64} func (c *circle) area() float64 { //面積  return math.Pi * c.radius * c.radius} func (c *circle) perimeter() float64 { //周長  return 2 * math.Pi * c.radius} // ----------- 接口的使用 -----------//func interface_test() {  r := rect {width:2.9, height:4.8}  c := circle {radius:4.3}   s := []shape{&r, &c} //通過指針實現   for _, sh := range s {    fmt.Println(sh)    fmt.Println(sh.area())    fmt.Println(sh.perimeter())  }}

錯誤處理 – Error接口

函數錯誤返回可能是C/C++時最讓人糾結的東西的,Go的多值返回可以讓我們更容易的返回錯誤,其可以在返回一個常規的返回值之外,還能輕易地返回一個詳細的錯誤描述。通常情況下,錯誤的類型是error,它有一個內建的接口。

type error interface {
Error() string
}

還是看個示例吧:

package main import "fmt"import "errors" //自定義的出錯結構type myError struct {  arg int  errMsg string}//實現Error接口func (e *myError) Error() string {  return fmt.Sprintf("%d - %s", e.arg, e.errMsg)} //兩種出錯func error_test(arg int) (int, error) {  if arg < 0 {     return -1, errors.New("Bad Arguments - negtive!")   }else if arg >256 {    return -1, &myError{arg, "Bad Arguments - too large!"}  }  return arg*arg, nil} //相關的測試func main() {  for _, i := range []int{-1, 4, 1000} {    if r, e := error_test(i); e != nil {      fmt.Println("failed:", e)    } else {      fmt.Println("success:", r)    }  }}

程序運行后輸出:

1 failed: Bad Arguments - negtive!
2 success: 16
3 failed: 1000 - Bad Arguments - too large!

錯誤處理 – Defer

下面的程序對于每一個熟悉C語言的人來說都不陌生(有資源泄露的問題),C++使用RAII來解決這種問題。

func CopyFile(dstName, srcName string) (written int64, err error) {  src, err := os.Open(srcName)  if err != nil {    return  }   dst, err := os.Create(dstName)  if err != nil {    return  }   written, err = io.Copy(dst, src)  dst.Close()  src.Close()  return}

Go語言引入了Defer來確保那些被打開的文件能被關閉。如下所示:(這種解決方式還是比較優雅的)

func CopyFile(dstName, srcName string) (written int64, err error) {  src, err := os.Open(srcName)  if err != nil {    return  }  defer src.Close()   dst, err := os.Create(dstName)  if err != nil {    return  }  defer dst.Close()   return io.Copy(dst, src)}

Go的defer語句預設一個函數調用(延期的函數),該調用在函數執行defer返回時立刻運行。該方法顯得不同常規,但卻是處理上述情況很有效,無論函數怎樣返回,都必須進行資源釋放。

我們再來看一個defer函數的示例:

1 for i := 0; i < 5; i++ {
2 defer fmt.Printf("%d ", i)
3 }

被延期的函數以后進先出(LIFO)的順行執行,因此以上代碼在返回時將打印4 3 2 1 0。

總之,我個人覺得defer的函數行為有點怪異,我現在還沒有完全搞清楚。

錯誤處理 – Panic/Recover

對于不可恢復的錯誤,Go提供了一個內建的panic函數,它將創建一個運行時錯誤并使程序停止(相當暴力)。該函數接收一個任意類型(往往是字符串)作為程序死亡時要打印的東西。當編譯器在函數的結尾處檢查到一個panic時,就會停止進行常規的return語句檢查。

下面的僅僅是一個示例。實際的庫函數應避免panic。如果問題可以容忍,最好是讓事情繼續下去而不是終止整個程序。

var user = os.Getenv("USER") func init() {  if user == "" {    panic("no value for $USER")  }}

當panic被調用時,它將立即停止當前函數的執行并開始逐級解開函數堆棧,同時運行所有被defer的函數。如果這種解開達到堆棧的頂端,程序就死亡了。但是,也可以使用內建的recover函數來重新獲得Go程的控制權并恢復正常的執行。 對recover的調用會通知解開堆棧并返回傳遞到panic的參量。由于僅在解開期間運行的代碼處在被defer的函數之內,recover僅在被延期的函數內部才是有用的。

你可以簡單地理解為recover就是用來捕捉Painc的,防止程序一下子就掛掉了。

下面是一個例程,很簡單了,不解釋了

func g(i int) {  if i>1 {    fmt.Println("Panic!")    panic(fmt.Sprintf("%v", i))  } } func f() {  defer func() {    if r := recover(); r != nil {      fmt.Println("Recovered in f", r)    }  }()   for i := 0; i < 4; i++ {    fmt.Println("Calling g with ", i)    g(i)    fmt.Println("Returned normally from g.")   }} func main() {  f()  fmt.Println("Returned normally from f.")}

運行結果如下:(我們可以看到Painc后的for循環就沒有往下執行了,但是main的程序還在往下走)

Calling g with 0Returned normally from g.Calling g with 1Returned normally from g.Calling g with 2Panic!Recovered in f 2Returned normally from f

總結

以上就是本文關于go語言基礎語法示例的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
伊人久久男人天堂| 国产999精品久久久| 一区二区福利视频| 亚洲最大av网| 丰满岳妇乱一区二区三区| 清纯唯美亚洲综合| 欧美不卡视频一区发布| 国产精品在线看| 爽爽爽爽爽爽爽成人免费观看| 亚洲网站在线观看| 亚洲精品中文字| 尤物精品国产第一福利三区| 国内精品小视频在线观看| 欧美日韩国产中文字幕| 欧洲日本亚洲国产区| 亚洲在线视频福利| 亚洲国产精品va在线看黑人动漫| 日本精品久久中文字幕佐佐木| 欧美理论在线观看| 91影院在线免费观看视频| 伊人久久大香线蕉av一区二区| 久久亚洲欧美日韩精品专区| 亚洲男人的天堂在线| 久久香蕉精品香蕉| 国产免费一区二区三区在线观看| 秋霞av国产精品一区| 久久久精品国产亚洲| 国产精品视频免费在线观看| 亚洲女同性videos| 激情久久av一区av二区av三区| 国产福利精品av综合导导航| 69国产精品成人在线播放| 欧美日韩免费一区| 亚洲欧美国产一本综合首页| 国产97免费视| 亚洲自拍中文字幕| 亚洲精品xxxx| 伊人伊成久久人综合网站| 国产亚洲免费的视频看| 日韩成人网免费视频| 精品久久久999| 欧美一级视频在线观看| 97久久伊人激情网| 视频在线观看99| 亚洲成在人线av| 亚洲欧美日韩在线一区| 色悠悠久久88| 国产在线视频一区| 成人动漫网站在线观看| 中文字幕在线看视频国产欧美在线看完整| 久久久久久12| 最近2019好看的中文字幕免费| 国产午夜精品全部视频在线播放| 欧美日韩国产一区在线| 亚洲视频欧美视频| 国产成人精品网站| 久久精品电影网| 亚洲人成欧美中文字幕| 亚洲一区二区日本| 亚洲综合在线做性| 亚洲人成啪啪网站| 国产精品入口免费视| 国产视频精品xxxx| 亚洲精品videossex少妇| 国产精品久久网| 91精品成人久久| 91免费版网站入口| 一区二区三区亚洲| 亚洲精品视频免费在线观看| 欧美二区乱c黑人| 亚洲激情中文字幕| 在线播放日韩精品| 国精产品一区一区三区有限在线| 久久综合久久八八| 国产精品黄色影片导航在线观看| 日韩精品在线观看网站| 色与欲影视天天看综合网| 精品香蕉一区二区三区| 欧美一区在线直播| 欧美性猛交xxxx黑人猛交| 日韩激情视频在线播放| 久久久电影免费观看完整版| 国产乱人伦真实精品视频| 欧美激情在线有限公司| 久久久精品一区二区三区| 欧美在线亚洲一区| 亚洲最大在线视频| 久久久免费av| 国产成人在线精品| 亚洲电影免费在线观看| 国产日韩av高清| 亚洲一区久久久| 亚洲国产精品福利| 亚洲一区二区三区香蕉| 亚洲欧美日韩精品| 亚洲国产精品久久久久秋霞不卡| 91久久综合亚洲鲁鲁五月天| 国产成人欧美在线观看| 亚洲午夜av久久乱码| 久久av中文字幕| 日韩黄色在线免费观看| 亚洲高清福利视频| 久久免费在线观看| 国产剧情久久久久久| 欧美在线视频网| 国产91网红主播在线观看| www.日韩欧美| 亚洲黄色av女优在线观看| 国产在线不卡精品| 欧美大尺度电影在线观看| 久久精品电影网站| 国产91免费看片| 日本国产欧美一区二区三区| 亚洲经典中文字幕| 国产精品露脸av在线| 国产精品第七影院| 精品国产欧美一区二区五十路| 国产在线视频2019最新视频| 亚洲欧美资源在线| 欧美激情亚洲国产| 久久精品国产亚洲精品2020| 国产精品三级网站| 亚洲色图欧美制服丝袜另类第一页| 成人久久一区二区三区| 亚洲性av网站| 亚洲国产97在线精品一区| 国产精品吴梦梦| 狠狠躁夜夜躁人人爽天天天天97| 78m国产成人精品视频| 亚洲午夜性刺激影院| 81精品国产乱码久久久久久| 国产精国产精品| 日韩大陆欧美高清视频区| 久久久久久久影视| 亚洲乱码国产乱码精品精| 国产精品热视频| 亚洲欧美另类在线观看| 国产精品露脸自拍| 在线观看欧美成人| www国产亚洲精品久久网站| 日韩视频免费大全中文字幕| 日韩精品亚洲精品| 久久电影一区二区| 中文字幕亚洲欧美日韩在线不卡| 国产精品免费观看在线| 国产精品看片资源| 91香蕉嫩草神马影院在线观看| 久久青草精品视频免费观看| 欧美激情精品久久久久| 欧美电影免费观看大全| 亚洲精品wwww| 久久久久久久色| 精品高清一区二区三区| 欧美电影免费播放| 久久久www成人免费精品张筱雨| 欧美成人剧情片在线观看| 国产mv久久久| 日韩av电影在线网| 456国产精品| 亚洲美女动态图120秒| 亚洲第一精品夜夜躁人人躁| 97**国产露脸精品国产| 欧美高清电影在线看| 91九色在线视频|