Java程序員Go語言入門指南

爲何是Go語言

  • 類C的語法,這意味着Java、C#、JavaScript程序員能很快的上手
  • 有本身的垃圾回收機制
  • 跨平臺、編譯便可執行無需安裝依賴環境
  • 支持反射

Go語言簡介

Go 語言(或 Golang)起源於 2007 年,並在 2009 年正式對外發布。Go 是很是年輕的一門語言,它的主要目標是「兼具Python等動態語言的開發速度和 C/C++ 等編譯型語言的性能與安全性」。html

數據類型

數據類型 說明
bool 布爾
string 字符串
int uint8,uint16,uint32,uint64,int8,int16,int32,int64
float float32,float64
byte byte

參考:www.runoob.com/go/go-data-…程序員

基本語法

HelloWorld

在線運行示例:play.golang.org/p/-4RylAqUV…golang

package main

import "fmt"

var name string

func init() {
  name = "world"
}

func main() {
  fmt.Println("hello " + name)
}
複製代碼

咱們來執行一下:shell

$ go run main.go # main.go 爲剛剛建立的那個文件的名稱
$ hello world
複製代碼

變量

變量聲明

在線運行示例:play.golang.org/p/zPqCkRZgr…編程

package main

import (
	"fmt"
)

func main() {
	var name string   // 聲明
	name = "da'mao'mao" // 賦值
	fmt.Println(name)

	var age int = 18 // 聲明並賦值
	fmt.Println(age)
}
複製代碼

類型推斷

在線運行示例:play.golang.org/p/0My8veBvt…安全

package main

import (
	"fmt"
)

func main() {
	name := "damaomao"
	fmt.Println(name)

	age := 18
	fmt.Println(age)
}
複製代碼

函數

  • 函數能夠有多個返回值
  • 隱式的指定函數是private仍是public,函數首字母大寫的爲public、小寫的爲private
  • 沒有相似Java中的try cachethrow,Go語言是經過將error做爲返回值來處理異常。
  • 不支持重載

下面咱們經過一個示例來了解一下,在線運行示例:play.golang.org/p/PYy3ueuPF…bash

package main

import (
	"errors"
	"fmt"
	"strconv"
)

func main() {
	log1()

	log2("hello world")

	ret1 := add1(1, 1)
	fmt.Println("add1 result:" + strconv.Itoa(ret1))

	ret2, err := Add2(0, 1)
	if err == nil {
		fmt.Println("Add2 result:" + strconv.Itoa(ret2))
	} else {
		fmt.Println("Add2 error", err)
	}
}

// 私有、無入參、無返回值
func log1() {
	fmt.Println("execute func log1")
}

// 私有、入參、無返回值
func log2(msg string) {
	fmt.Println("execute func log2:" + msg)
}

// 私有、兩個入參、一個返回值
func add1(count1, count2 int) int {
	total := count1 + count2
	fmt.Println("execute func add3, result=" + strconv.Itoa(total))
	return total
}

// Public、兩個入參、多個返回值
func Add2(count1, count2 int) (int, error) {
	if count1 < 1 || count2 < 1 {
		return 0, errors.New("數量不能小於1")
	}
	total := count1 + count2
	return total, nil
}
複製代碼

該示例輸出結果爲:架構

execute func log1
execute func log2:hello world
execute func add3, result=2
add1 result:2
Add2 error 數量不能小於1
複製代碼

但函數有多個返回值的時候,有時你只關注其中一個返回值,這種狀況下你能夠將其餘的返回值賦值給空白符:_,以下:併發

_, err := Add2(1, 2)
if err != nil {
  fmt.Println(err)
}	
複製代碼

空白符特殊在於實際上返回值並無賦值,因此你能夠隨意將不一樣類型的值賦值給他,而不會因爲類型不一樣而報錯。異步

結構體

Go語言不是像Java那樣的面向對象的語言,他沒有對象和繼承的概念。也沒有class的概念。在Go語言中有個概念叫作結構體(struct),結構體和Java中的class比較相似。下面咱們定義一個結構體:

type User struct {
	Name   string
	Gender string
	Age    int
}
複製代碼

上面咱們定義了一個結構體User,併爲該結構體分別設置了三個公有屬性:Name/Gender/Age,下面咱們來建立一個User對象。

user := User{
	Name:   "hahaha",
	Gender: "男",
	Age:    18, // 值得一提的是,最後的逗號是必須的,不然編譯器會報錯,這就是go的設計哲學之一,要求強一致性。
}
複製代碼

結構體的屬性能夠在結構體內直接聲明,那麼如何爲結構體聲明函數(即Java中的方法)呢,咱們來看下下面的示例:在線運行示例:play.golang.org/p/01_cTu0Rz…

package main

import "fmt"

type User struct {
	Name   string
	Gender string
	Age    int
}

// 定義User的成員方法
func (u *User) addAge() {
	u.Age = u.Age + 1
}

func main() {
	user := User{
		Name:   "哈", // 名稱
		Gender: "男", // 性別
		Age:    18,  // 值得一提的是,最後的逗號是必須的,不然編譯器會報錯,這就是go的設計哲學之一,要求強一致性。
	}
	user.addAge()
	fmt.Println(user.Age)
}
複製代碼

指針類型和值類型

Java中值類型和引用類型都是定死的,int、double、float、long、byte、short、char、boolean爲值類型,其餘的都是引用類型,而Go語言中卻不是這樣。

在Go語言中:

  • &表示取地址,例如你有一個變量a那麼&a就是變量a在內存中的地址,對於Golang指針也是有類型的,好比a是一個string那麼&a是一個string的指針類型,在Go裏面叫&string。
  • *表示取值,接上面的例子,假設你定義b := &a 若是你打印b,那麼輸出的是&a的內存地址,若是要取值,那麼須要使用:*b

下面咱們來看下例子,在線運行:play.golang.org/p/jxAKyVMjn…

package main

import (
	"fmt"
)

func main() {
	a := "123"
	b := &a

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(*b)
}

輸出結果爲:
123
0x40c128
123
複製代碼

併發編程

Go語言的併發是基於 goroutine 的,goroutine 相似於線程,但並不是線程。能夠將 goroutine 理解爲一種虛擬線程。Go語言運行時會參與調度 goroutine,並將 goroutine 合理地分配到每一個 CPU 中,最大限度地使用CPU性能。

Go 程序從 main 包的 main() 函數開始,在程序啓動時,Go 程序就會爲 main() 函數建立一個默認的 goroutine。

下面咱們來看一個例子(在線演示:play.golang.org/p/U9U-qjuY0…

package main

import (
	"fmt"
	"time"
)

func main() {
	// 建立一個goroutine
	go runing()
	// 建立一個匿名的goroutine
	go func() {
		fmt.Println("喜特:" + time.Now().String())
	}()

	// 這裏sleep一下是由於main方法若是執行完了,main該程序建立的全部goroutine都會退出
	time.Sleep(5 * time.Second)
}

func runing() {
	fmt.Println("法克:" + time.Now().String())
	time.Sleep(3 * time.Second)
}

輸出:
法克:2009-11-10 23:00:00 +0000 UTC m=+0.000000001
喜特:2009-11-10 23:00:00 +0000 UTC m=+0.000000001
複製代碼

執行結果說明fuck函數中的sleep三秒並無影響喜特的輸出。

若是說 goroutine 是Go語言程序的併發體的話,那麼 channel 就是它們之間的通訊機制。一個 channel 是一個通訊機制,它可讓一個 goroutine 經過它給另外一個 goroutine 發送值信息。每一個 channel 都有一個特殊的類型,也就是 channel 可發送數據的類型。一個能夠發送 int 類型數據的 channel 通常寫爲 chan int。

下面咱們利用goroutine+channel來實現一個生產消費者模型,示例代碼以下:(在線執行:play.golang.org/p/lqUBugLdU…

package main

import (
	"fmt"
	"time"
)

func main() {
	// 建立一個通道
	channel := make(chan int64)

	// 異步去生產
	go producer(channel)

	// 數據消費
	consumer(channel)
}

// 生產者
func producer(channel chan<- int64) {
	for {
		// 將數據寫入通道
		channel <- time.Now().Unix()
		// 睡1秒鐘
		time.Sleep(time.Second)
	}
}

// 消費者
func consumer(channel <-chan int64) {
	for {
		timestamp := <-channel
		fmt.Println(timestamp)
	}
}

輸出爲以下:(每秒鐘打印一次)
1257894000
1257894001
1257894002
1257894003
複製代碼

Java程序員以爲很差用的地方

  • 異常處理
  • 沒有泛型
  • 不支持多態、重載
  • 不支持註解(可是他的struct中的屬性支持tag

參考

做者簡介

大貓貓,互聯網公司老碼農、不折騰不舒服斯基,多年千萬日活服務端研發和架構經驗。

  • 碼農俱樂部:mlog.club
  • 關注公衆號查看更多幹貨

碼農俱樂部
相關文章
相關標籤/搜索