chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

從 Java 到 Go:面向?qū)ο蟮木奕伺c云原生的輕騎兵

京東云 ? 來(lái)源:jf_75140285 ? 作者:jf_75140285 ? 2025-04-25 11:13 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Go 語(yǔ)言在 2009 年被 Google 推出,在創(chuàng)建之初便明確提出了“少即是多(Less is more)”的設(shè)計(jì)原則,強(qiáng)調(diào)“以工程效率為核心,用極簡(jiǎn)規(guī)則解決復(fù)雜問(wèn)題”。它與 Java 語(yǔ)言生態(tài)不同,Go 通過(guò)編譯為 單一靜態(tài)二進(jìn)制文件實(shí)現(xiàn)快速啟動(dòng)和低內(nèi)存開(kāi)銷(xiāo)以25個(gè)關(guān)鍵字強(qiáng)制代碼簡(jiǎn)潔性,接口組合替代類(lèi)繼承以顯式返回error取代異常機(jī)制輕量級(jí)并發(fā)模型(Goroutine/Channel)云原生基礎(chǔ)設(shè)施領(lǐng)域 占據(jù)主導(dǎo)地位,它也是 Java 開(kāi)發(fā)者探索云原生技術(shù)棧的關(guān)鍵補(bǔ)充。本文將對(duì) Go 語(yǔ)言和 Java 語(yǔ)言在一些重要特性上進(jìn)行對(duì)比,為 Java 開(kāi)發(fā)者在閱讀和學(xué)習(xí) Go 語(yǔ)言相關(guān)技術(shù)時(shí)提供參考。

代碼組織的基本單元

在 Java 中,我們會(huì)創(chuàng)建 .java 文件作為 類(lèi)(類(lèi)名與文件名相同),并在該類(lèi)中定義相關(guān)的字段或方法等(OOP),如下定義 User 和 Address 相關(guān)的內(nèi)容便需要聲明兩個(gè) .java 文件(User.java, Address.java)定義類(lèi):

public class User {

    private String name;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public class Address {
    private String city;
    
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
}

而在 Go 語(yǔ)言中,它是通過(guò) “包” 來(lái)組織代碼的:每個(gè)目錄下的所有 .go 文件共享同一個(gè) ,在包內(nèi)可以定義多個(gè)結(jié)構(gòu)體、接口、函數(shù)或變量。它并不要求文件名與聲明的內(nèi)容一致,比如創(chuàng)建 User “結(jié)構(gòu)體”并不會(huì)要求 .go 文件也命名為 User.go,而是任何命名都可以(命名為 user.go 甚至 a.go 這種無(wú)意義的命名),而且同一個(gè)包下可以創(chuàng)建多個(gè) .go 文件。如下為在 user 包下定義 User 和 Address 相關(guān)的內(nèi)容,它們都被聲明在一個(gè) user.go 文件中:

package user

type User struct {
   name string
}

func (u *User) Name() string {
   return u.name
}

func (u *User) SetName(name string) {
   u.name = name
}

type Address struct {
   city string
}

func (a *Address) City() string {
   return a.city
}

func (a *Address) SetCity(city string) {
   a.city = city
}

相比來(lái)說(shuō),Java 代碼組織的基本單元是類(lèi),作為面向?qū)ο蟮恼Z(yǔ)言更側(cè)重對(duì)象定義,而 Go 代碼組織的基本單元是包,并更側(cè)重功能模塊的聚合。

可見(jiàn)性控制

在 Java 中通過(guò) public/protected/private 關(guān)鍵字控制成員的可見(jiàn)性,而在 Go 語(yǔ)言中,通過(guò) 首字母大小寫(xiě) 控制“包級(jí)別的導(dǎo)出”(大寫(xiě)字母開(kāi)頭為 public),包的導(dǎo)出成員對(duì)其他包可見(jiàn)。以 user 包下 User 類(lèi)型的定義為例,在 main 包下測(cè)試可見(jiàn)性如下:

package main

import (
	"fmt"
	// user package 的全路徑
	"learn-go/src/com/github/user"
   // 不能導(dǎo)入未使用到的包
   //"math"
)

func main() {
	var u user.User
	// 在這里是不能訪問(wèn)未導(dǎo)出的字段 name
	// fmt.Println(u.name)
	fmt.Println(u.Name())
}

Go 語(yǔ)言不能導(dǎo)入未使用到的包,并且函數(shù)是基于包的一部分。比如 fmt.Println 函數(shù),這個(gè)函數(shù)是在 fmt 包下的,調(diào)用時(shí)也是以包名為前綴。

變量的聲明

在 Java 語(yǔ)言中,對(duì)變量(靜態(tài)變量或局部變量)的聲明只有一種方式,“采用 = 運(yùn)算符賦值”顯式聲明(在 Jdk 10+支持 var 變量聲明),如下:

public class Test {
    public static void main(String[] args) {
        int x = 100;
    }
}

而在 Go 語(yǔ)言中,變量聲明有兩種主要方式:短聲明(:= 運(yùn)算符)長(zhǎng)聲明(var 聲明),它們的適用場(chǎng)景和限制有所不同,以下是詳細(xì)區(qū)分:

短聲明(:=)

只能在函數(shù)(包括 main、自定義函數(shù)或方法、if/for 塊等)內(nèi)部使用,不能在包級(jí)別(全局作用域)使用,并且 聲明的局部變量必須被使用,不被使用的局部變量不能被聲明:

package main

import "fmt"

func main() {
	// 正確
	x := 10
	fmt.Println(x)
	// 未被使用,不能被聲明
	// y := 20
	// 不賦值也不能被聲明
	// z :=            
}

// 錯(cuò)誤:不能在包級(jí)別使用短聲明
// y := 20          

這種短聲明直接根據(jù)右側(cè)值自動(dòng)推斷變量類(lèi)型,無(wú)需顯式指定類(lèi)型,并且可以一次性聲明多個(gè)變量,但至少有一個(gè)變量是 新聲明的

package main

import "fmt"

func main() {
	// 同時(shí)聲明 a 和 b
	a, b := 1, "abc"
	// c 是新變量,b 被重新賦值
	c, b := 2, "def"
	// 無(wú)新變量無(wú)法再次對(duì)已聲明的變量再次聲明
	//a, b := 4, "error"
	
	fmt.Println(a, b, c)
}

長(zhǎng)聲明(var 聲明)

在全局作用域聲明變量必須使用 var;在需要延遲初始化時(shí)也需要采用長(zhǎng)聲明;顯示指定類(lèi)型也需要使用長(zhǎng)聲明

package main

import "fmt"

var global int = 42

func main() {
	// a = 0
	var a int
	// s = ""
	var s string
	// 未被初始化值會(huì)默認(rèn)為“零”值,a 為 0,s 為空字符串
	fmt.Println(a, s)
}

函數(shù)內(nèi)部的局部變量,尤其是需要類(lèi)型推斷和簡(jiǎn)潔代碼時(shí)優(yōu)先用短聲明;在包級(jí)別聲明變量,需要顯式指定類(lèi)型或聲明變量但不立即賦值(零值初始化)時(shí),使用長(zhǎng)聲明。

在 Go 語(yǔ)言中還有一點(diǎn)需要注意:聲明變量時(shí),應(yīng)確保它與任何現(xiàn)有的函數(shù)、包、類(lèi)型或其他變量的名稱(chēng)不同。如果在封閉范圍內(nèi)存在同名的東西,變量將對(duì)它進(jìn)行覆蓋,也就是說(shuō),優(yōu)先于它,如下所示:

package main

import "fmt"

func main() {
    // 這個(gè)變量會(huì)把導(dǎo)入的 fmt 包覆蓋掉
	fmt := 1
	println(fmt)
}

那么我們導(dǎo)入的 fmt 包在被局部變量覆蓋后便不能再被使用了。

常量的聲明

Go 語(yǔ)言中對(duì)常量的聲明采用 const 關(guān)鍵字,并且在聲明時(shí)便需要被賦值,如下所示:

package main

import "fmt"

// DaysInWeek const 變量名 類(lèi)型 = 具體的值
const DaysInWeek int = 7

func main() {
   const name = "abc"
   fmt.Println(name, DaysInWeek)
}

在 Java 語(yǔ)言中對(duì)常量的聲明會(huì)使用 static final 引用:

public class Constants {
    public static final int DAYS_IN_WEEK = 7;
    
    // ...
}

方法/函數(shù)的聲明

在 Go 語(yǔ)言中,方法的聲明遵循 func (接收器) 方法名(入?yún)? 返回值 的格式,無(wú)返回值可以不寫(xiě)(無(wú)需 void 聲明),通過(guò) 接收器(Receiver) 將方法綁定到結(jié)構(gòu)體上,如下為 User 結(jié)構(gòu)體方法的聲明:

package user

type User struct {
	name string
}

// Name (u *User) 即為接收器,表示該方法綁定在了 User 類(lèi)型上
func (u *User) Name() string {
	return u.name
}

func (u *User) SetName(name string) {
	u.name = name
}

而“函數(shù)”的聲明不需要定義接收器,遵循的是 func 方法名(入?yún)? 返回值 的格式。Go 語(yǔ)言中的函數(shù)類(lèi)似于 Java 語(yǔ)言中的靜態(tài)方法,以下是聲明將整數(shù)擴(kuò)大兩倍的函數(shù):

package main

func double(a *int) {
	*a *= 2
}

并且,在 Go 語(yǔ)言中,方法/函數(shù)支持多返回值(常用于錯(cuò)誤處理),并且如果并不需要全部的返回值,可以用 _ 對(duì)返回值進(jìn)行忽略,因?yàn)镚o語(yǔ)言不允許定義未使用的局部變量,如下所示:

package main

import "fmt"

func main() {
	// 忽略掉了第三個(gè)返回值
	s1, s2, _, e := multiReturn()
	if e == nil {
		fmt.Println(s1, s2)
	}
}

func multiReturn() (string, string, string, error) {
	return "1", "2", "2", nil
}

此外,接收器參數(shù)和函數(shù)的形參支持傳入指針,用 * 符號(hào)表示。在 Go 語(yǔ)言中有指針的概念,我們?cè)谶@里說(shuō)明一下:Go 語(yǔ)言是 “值傳遞” 語(yǔ)言,方法/函數(shù)的形參(或接收器)如果不標(biāo)記指針的話(huà),接收的實(shí)際上都是 實(shí)參的副本,那么 在方法/函數(shù)中的操作并不會(huì)對(duì)原對(duì)象有影響。如果想對(duì)原對(duì)象進(jìn)行操作,便需要通過(guò)指針獲取到原對(duì)象才行(因?yàn)橹祩鬟f會(huì)對(duì)原對(duì)象和形參對(duì)象都劃分空間,所以針對(duì)較大的對(duì)象都推薦使用指針以節(jié)省內(nèi)存空間)。在如下示例中,如果我們將上文中 double 方法的形參修改為值傳遞,這樣是不能將變量 a 擴(kuò)大為兩倍的,因?yàn)樗僮鞯氖?a 變量的副本:

package main

import "fmt"

func main() {
	a := 5
	double(a)
	// 想要獲取 10,但打印 5
	fmt.Println(a)
}

func double(a int) {
	a *= 2
}

想要實(shí)現(xiàn)對(duì)原對(duì)象 a 的操作,便需要使用指針操作,將方法的聲明中傳入指針變量 *int:

package main

import "fmt"

func main() {
	a := 5
	// & 為取址運(yùn)算符
	double(&a)
	// 想要獲取 10,實(shí)際獲取 10
	fmt.Println(a)
}

// *int 表示形參 a 傳入的是指針
func double(a *int) {
	// *a 表示從地址中獲取變量 a 的值
	*a *= 2
}

再回到 User 類(lèi)型的聲明中,如果我們將接收器修改成 User,那么 SetName 方法是不會(huì)對(duì)原變量進(jìn)行修改的,它的修改實(shí)際上只針對(duì)的是 User 的副本:

package user

type User struct {
	name string
}

// SetName 指定為值接收器
func (u User) SetName(name string) {
	u.name = name
}

這樣 SetName 方法便不會(huì)修改原對(duì)象,SetName 的操作也僅僅對(duì)副本生效了:

package main

import (
	"fmt"
	"learn-go/src/com/github/user"
)

func main() {
	u := user.User{}
	u.SetName("abc")
	// 實(shí)際輸出為 {},并沒(méi)有對(duì)原對(duì)象的 name 字段完成賦值
	fmt.Println(u)
}

在 Java 中并沒(méi)有指針的概念,Java 中除了基本數(shù)據(jù)類(lèi)型是值傳遞外,其他類(lèi)型在方法間傳遞的都是“引用”,對(duì)引用對(duì)象的修改也是對(duì)原對(duì)象的修改。

接口

Go 語(yǔ)言也支持接口的聲明,不過(guò)相比于 Java 語(yǔ)言它更追求 “靈活與簡(jiǎn)潔”。Go 的接口實(shí)現(xiàn)是“隱式地”,只要類(lèi)型實(shí)現(xiàn)了接口的所有方法,就自動(dòng)滿(mǎn)足該接口,無(wú)需顯式聲明。如下:

package writer

type Writer interface {
   Write([]byte) (int, error)
}

// File 無(wú)需聲明實(shí)現(xiàn) Writer,實(shí)現(xiàn)了接口所有的方法便自動(dòng)實(shí)現(xiàn)了該接口
type File struct{}

func (f *File) Write(data []byte) (int, error) {
   return len(data), nil
}

Java 語(yǔ)言則必須通過(guò) implements 關(guān)鍵字聲明類(lèi)對(duì)接口的實(shí)現(xiàn):

public interface Writer {
   int write(byte[] data);
}

public class File implements Writer {  // 必須顯式聲明
   @Override
   public int write(byte[] data) {
      return data.length;
   }
}

它們對(duì)類(lèi)型的判斷也是不同的,在 Go 語(yǔ)言中采用如下語(yǔ)法:

package writer

func typeTransfer() {
   var w Writer = File{}
   // 判斷是否為 File 類(lèi)型,如果是的話(huà) ok 為 true
   f, ok := w.(File)
   if ok {
      f.Write(data)
   }
}

而在 Java 語(yǔ)言中則采用 instanceof 和強(qiáng)制類(lèi)型轉(zhuǎn)換:

private void typeTransfer() {
   Writer w = new File();
   if (w instanceof File) {
      File f = (File) w;
      f.write(data);
   }
}

Go 語(yǔ)言還采用空接口 interface{} 來(lái)表示任意類(lèi)型,作為方法入?yún)r(shí)則支持任意類(lèi)型方法的傳入,類(lèi)似 Java 中的 Object 類(lèi)型:

package writer

func ProcessData(data interface{}) {
	// ...
}

除此之外,Go 語(yǔ)言在 1.18+ 版本引入了泛型,采用 [T any] 方括號(hào)語(yǔ)法定義類(lèi)型約束,any 表示任意類(lèi)型,如果采用具體類(lèi)型限制則如下所示:

package writer

// Stringer 定義約束:要求類(lèi)型支持 String() 方法
type Stringer interface {
    String() string
}

func ToString[T Stringer](v T) string {
    return v.String()
}

通過(guò)類(lèi)型的限制便能使用類(lèi)型安全替代空接口 interface{},避免運(yùn)行時(shí)類(lèi)型斷言:

// 舊方案:空接口 + 類(lèi)型斷言
func OldMax(a, b interface{}) interface{} {
    // 需要手動(dòng)斷言類(lèi)型,易出錯(cuò)
}

// 新方案:泛型
func NewMax[T Ordered](a, b T) T { /* 直接比較 */ }

泛型還在通用數(shù)據(jù)結(jié)構(gòu)上有廣泛的應(yīng)用:

type Stack[T any] struct {
    items []T
}
func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

基本數(shù)據(jù)類(lèi)型

Go 的基本數(shù)據(jù)類(lèi)型分為 4 大類(lèi),相比于 Java 更簡(jiǎn)潔且明確:

類(lèi)別 具體類(lèi)型 說(shuō)明
數(shù)值型 int, int8, int16, int32, int64 Go 的 int 長(zhǎng)度由平臺(tái)決定(32 位系統(tǒng)為 4 字節(jié),64 位為 8 字節(jié)),有符號(hào)整數(shù)(位數(shù)明確,如 int8 占 1 字節(jié))
uint, uint8, uint16, uint32, uint64, uintptr 無(wú)符號(hào)整數(shù)(uintptr 用于指針運(yùn)算)
float32, float64 浮點(diǎn)數(shù)(默認(rèn) float64)
complex64, complex128 復(fù)數(shù)(實(shí)部和虛部分別為 float32 或 float64,Java 無(wú)此類(lèi)型)
布爾型 bool 僅 true/false(不可用 0/1 替代)
字符串 string 不可變的 UTF-8 字符序列
派生型 byte(=uint8) 1 字節(jié)數(shù)據(jù)
rune(=int32) Go 語(yǔ)言的字符(rune)使用 Unicode 來(lái)存儲(chǔ),而并不是字符本身,如果把 rune 傳遞給 fmt.Println 方法,會(huì)在控制臺(tái)看到數(shù)字。雖然 Java 語(yǔ)言同樣以 Unicode 保存字符(char),不過(guò)它會(huì)在控制臺(tái)打印字符信息

Go 和 Java 同樣都是 靜態(tài)類(lèi)型語(yǔ)言,要求在 編譯期 確定所有變量的類(lèi)型,且類(lèi)型不可在運(yùn)行時(shí)動(dòng)態(tài)改變。Go 不允許任何隱式類(lèi)型轉(zhuǎn)換(如 int32 到 int64),但是在 Java 中允許基本類(lèi)型隱式轉(zhuǎn)換(如 int → long),除此之外,Go 語(yǔ)言會(huì)嚴(yán)格區(qū)分類(lèi)型別名(如 int 與 int32 不兼容)。在 Go 語(yǔ)言中如果需要將不同類(lèi)型的變量進(jìn)行計(jì)算,需要進(jìn)行類(lèi)型轉(zhuǎn)換:

package main

import "fmt"

func main() {
	a := 1
	b := 2.2
	// 如果不類(lèi)型轉(zhuǎn)換則不能通過(guò)編譯
	fmt.Println(float64(a) * b)
}

“引用類(lèi)型”

在 Go 語(yǔ)言中,嚴(yán)格來(lái)說(shuō)并沒(méi)有“引用類(lèi)型”這一官方術(shù)語(yǔ),但在 Go 語(yǔ)言社區(qū)中通常將 Slice(切片)、Map(映射)、Channel(通道) 稱(chēng)為“引用語(yǔ)義類(lèi)型”(或簡(jiǎn)稱(chēng)引用類(lèi)型),因?yàn)樗鼈兊男袨榕c傳統(tǒng)的引用類(lèi)型相似,在未被初始化時(shí)為 nil,并無(wú)特定的“零值”。除了這三種類(lèi)型之外,Go 的其他類(lèi)型(如結(jié)構(gòu)體、數(shù)組、基本類(lèi)型等)都是 值類(lèi)型

Slice

Go 的 Slice 本質(zhì)上是動(dòng)態(tài)數(shù)組的抽象,基于底層數(shù)組實(shí)現(xiàn)自動(dòng)擴(kuò)容。它類(lèi)似于 Java 中的 ArrayList,采用 var s []int 或 s := make([]int, 5) 聲明,如下:

package main

import "fmt"

func slice() {
  // 初始化到小為 0 的切片
  s := make([]int, 0)
  // 動(dòng)態(tài)追加元素
  s = append(s, 1, 2, 3, 4, 5)
  fmt.Println(s)
  // 子切片,左閉右開(kāi)區(qū)間 sub = {2, 3}
  sub := s[1:3]
  fmt.Println(sub)
  // 修改子切片值會(huì)影響到 s 原數(shù)組
  sub[0] = 99
  fmt.Println(s)
}

切片的底層數(shù)組并不能增長(zhǎng)大小。如果數(shù)組沒(méi)有足夠的空間來(lái)保存新的元素,所有的元素會(huì)被拷貝至一個(gè)新的更大的數(shù)組,并且切片會(huì)被更新為引用這個(gè)新的數(shù)組。但是由于這些場(chǎng)景都發(fā)生在 append 函數(shù)內(nèi)部,所發(fā)知道返回的切片和傳入 append 函數(shù)的切片是否為相同的底層數(shù)組,所以如果保留了兩個(gè)切片,那么這一點(diǎn)需要注意。

Map

Go 的 Map 本質(zhì)上是無(wú)序鍵值對(duì)集合,基于哈希表實(shí)現(xiàn)。它的鍵必須支持 == 操作(如基本類(lèi)型、結(jié)構(gòu)體、指針),聲明方式為 m := make(map[string]int) 或 m := map[string]int{"a": 1},它與 Java 中的 HashMap 類(lèi)似,如下所示:

package main

import "fmt"

func learnMap() {
  m := make(map[string]int)
  m["a"] = 1
  // 安全的讀取
  value, ok := m["a"]
  if ok {
    fmt.Println(value)
  }
  delete(m, "a")
}

Channel

Go 的 Channel 是用于 協(xié)程(goroutine,Go 語(yǔ)言中的并發(fā)任務(wù)類(lèi)似 Java 中的線(xiàn)程)間通信 的管道,支持同步或異步數(shù)據(jù)傳輸。無(wú)緩沖區(qū)通道會(huì)阻塞發(fā)送/接收操作,直到另一端就緒。它的聲明方式為 channel := make(chan string)(無(wú)緩沖)或 channel := make(chan string, 3)(有緩沖,緩沖區(qū)大小為 3),創(chuàng)建無(wú)緩存區(qū)的 channel 示例如下:

package main

import "fmt"

// 創(chuàng)建沒(méi)有緩沖區(qū)的 channel,如果向其中寫(xiě)入值后而沒(méi)有其他協(xié)程從中取值,
// 再向其寫(xiě)入值的操作則會(huì)被阻塞,也就是說(shuō)“發(fā)送操作會(huì)阻塞發(fā)送 goroutine,直到另一個(gè) goroutine 在同一 channel 上執(zhí)行了接收操作”
// 反之亦然
func channel() {
  channel1 := make(chan string)
  channel2 := make(chan string)

  // 啟動(dòng)一個(gè)協(xié)程很簡(jiǎn)單,即 go 關(guān)鍵字和要調(diào)用的函數(shù)
  go abc(channel1)
  go def(channel2)

  // 

如果創(chuàng)建有緩沖的 channel,在我們的例子中,那么就可以實(shí)現(xiàn)寫(xiě)入?yún)f(xié)程不必等待 main 協(xié)程的接收操作了:

package main

import "fmt"

func channelNoBlocked() {
	// 表示創(chuàng)建緩沖區(qū)大小為 3 的 channel,并且 channel 傳遞的類(lèi)型為 string
	channel1 := make(chan string, 3)
	channel2 := make(chan string, 3)

	go abc(channel1)
	go def(channel2)

	// 輸出一直都會(huì)是 adbecf
	fmt.Print(

在 Go 中創(chuàng)建上述三種引用類(lèi)型的對(duì)象時(shí),都使用了 make 函數(shù),它是專(zhuān)門(mén)用于初始化這三種引用類(lèi)型的,如果不使用該函數(shù),直接聲明(如var m map[string]int)會(huì)得到 nil 值,而無(wú)法直接操作。它與 Java 中的 new 關(guān)鍵字操作有很大的區(qū)別,new 關(guān)鍵字會(huì)為對(duì)象分配內(nèi)存 并調(diào)用構(gòu)造函數(shù)(初始化邏輯在構(gòu)造函數(shù)中),而在 Go 的設(shè)計(jì)中是沒(méi)有構(gòu)造函數(shù)的,Go 語(yǔ)言除了這三種引用類(lèi)型,均為值類(lèi)型,直接聲明即可,聲明時(shí)便會(huì)直接分配內(nèi)存并初始化為零值。

從失敗中恢復(fù)

在 Go 語(yǔ)言中 沒(méi)有傳統(tǒng)“異?!备拍?/strong>,它不依賴(lài) try/catch,而是通過(guò) 顯式返回錯(cuò)誤值 和 panic/recover 機(jī)制處理。它的錯(cuò)誤(error)也是普通的數(shù)據(jù),能夠作為值傳遞。在多數(shù)方法中能看到如下類(lèi)似的實(shí)現(xiàn):

package main

func main() {
	data, err := ReadFile("file.txt")
	// 處理錯(cuò)誤
	if err != nil {
		log.Fatal(err)
	}
	// ...
}

func ReadFile(path string) ([]byte, error) {
    // 成功返回 data, nil
    // 失敗返回 nil, error
}

Go 語(yǔ)言使用 panic 來(lái)處理不可恢復(fù)的或程序無(wú)法繼續(xù)運(yùn)行的錯(cuò)誤(如數(shù)組越界、空指針),這類(lèi)似于 Java 語(yǔ)言中的 throw 異常,它會(huì)中斷方法或函數(shù)的執(zhí)行,向上拋出直到遇到 defer 和 recover() 函數(shù)的聲明捕獲或者程序崩潰:

// 初始化失敗時(shí)觸發(fā) panic
func initDatabase() {
    if !checkDatabaseConnection() {
        panic("Database connection failed!")
    }
}

// 通過(guò) recover 捕獲 panic
func main() {
	// 延遲函數(shù)的執(zhí)行
    defer func() {
		// 使用 recover() 函數(shù)嘗試捕獲異常 
        if r := recover(); r != nil {
            fmt.Println("Recovered from panic:", r)
        }
    }()
    initDatabase()
    // 正常邏輯...
}

defer 關(guān)鍵字 必須修飾的函數(shù)或方法,而且被這個(gè)關(guān)鍵字修飾的函數(shù)或方法 一旦注冊(cè) 無(wú)論如何都會(huì)被執(zhí)行(類(lèi)似于 Java 中的 finally),但如果 defer 聲明在函數(shù)尾部,但函數(shù)在運(yùn)行到該 defer 語(yǔ)句之前就退出(例如中途 return 或 panic),則 defer 不會(huì)注冊(cè),也不會(huì)執(zhí)行。所以該關(guān)鍵字在資源被初始化之后應(yīng)該立即使用,而非像 Java 一樣聲明在方法的尾部。而且 defer 支持聲明多個(gè),但執(zhí)行的順序是逆序的。

revocer() 函數(shù)與 defer 關(guān)鍵字搭配使用,它會(huì)返回函數(shù)執(zhí)行過(guò)程中拋出的 panic(未發(fā)生 panic 時(shí)會(huì)為 nil),可以幫助開(kāi)發(fā)者恢復(fù)或提供有用的異常信息。

以下是在文件讀取場(chǎng)景 Go 和 Java 語(yǔ)言在語(yǔ)法上的不同:

Go

func readFile() {
    file, err := os.Open("file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    // 處理文件內(nèi)容
}

Java

public void readFile() {
    // try-with-resources
    try (FileReader file = new FileReader("file.txt")) {
        // 處理文件內(nèi)容
    } catch (IOException e) {
        System.err.println("Error: " + e.getMessage());
    }
}

問(wèn):我看到其他編程語(yǔ)言有 exception。panic 和 recover 函數(shù)似乎以類(lèi)似的方式工作。我可以把它們當(dāng)作 exception 來(lái)使用嗎?

答:Go語(yǔ)言維護(hù)者強(qiáng)烈建議不要這樣做。甚至可以說(shuō),語(yǔ)言本身的設(shè)計(jì)不鼓勵(lì)使用 panic和 recover。在 2012 年的一次主題會(huì)議上,RobPike(Go的創(chuàng)始人之一)把 panic 和 recover 描述為“故意笨拙”。這意味著,在設(shè)計(jì) Go 時(shí),創(chuàng)作者們沒(méi)有試圖使 panic 和 recover 被容易或愉快地使用,因此它們會(huì)很少使用。這是 Go 設(shè)計(jì)者對(duì) exception 的一個(gè)主要弱點(diǎn)的回應(yīng):它們可以使程序流程更加復(fù)雜。相反,Go 開(kāi)發(fā)人員被鼓勵(lì)以處理程序其他部分的方式處理錯(cuò)誤:使用 if 和 return 語(yǔ)句,以及 error 值。當(dāng)然,直接在函數(shù)中處理錯(cuò)誤會(huì)使函數(shù)的代碼變長(zhǎng),但這比根本不處理錯(cuò)誤要好得多。(Go的創(chuàng)始人發(fā)現(xiàn),許多使用 exception 的開(kāi)發(fā)人員只是拋出一個(gè) exception,之后并沒(méi)有正確地處理它。)直接處理錯(cuò)誤也使錯(cuò)誤的處理方式一目了然,你不必查找程序的其他部分來(lái)查看錯(cuò)誤處理代碼。所以不要在 Go 中尋找等同于 exception 的東西。這個(gè)特性被故意省略了。對(duì)于習(xí)慣了使用 exception 的開(kāi)發(fā)人員來(lái)說(shuō),可能需要一段時(shí)間的調(diào)整,但 Go 的維護(hù)者相信,這最終會(huì)使軟件變得更好。

for 和 if

for

Go 語(yǔ)言的循環(huán)語(yǔ)法只有 for,沒(méi)有 while 或 do-while,但可實(shí)現(xiàn)所有循環(huán)模式:

// 1. 經(jīng)典三段式(類(lèi)似 Java 的 for 循環(huán))
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

// 2. 類(lèi)似 while 循環(huán)(條件在前)
sum := 0
for sum < 10 {
    sum += 2
}

// 3. 無(wú)限循環(huán)(省略條件)
for {
    fmt.Println("Infinite loop")
    break  // 需手動(dòng)退出
}

// 4. 遍歷集合,采用 range 關(guān)鍵字,index 和 value 分別表示索引和值
arr := []int{1, 2, 3}
for index, value := range arr {
    fmt.Printf("Index: %d, Value: %dn", index, value)
}

if

Go 語(yǔ)言的 if 語(yǔ)法相比于 Java 支持聲明 + 條件的形式,并且強(qiáng)制要求大括號(hào)(即使是單行語(yǔ)句也必須使用 {}):

// 支持簡(jiǎn)短聲明(聲明 + 條件)
if num := 10; num > 5 {  
    fmt.Println("num is greater than 5")
}
// 簡(jiǎn)單判斷
if num > 5 {
    fmt.Println("num is greater than 5")
}

巨人的肩膀

《Head First Go 語(yǔ)言程序設(shè)計(jì)》

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2992

    瀏覽量

    114726
  • Go
    Go
    +關(guān)注

    關(guān)注

    0

    文章

    45

    瀏覽量

    12495
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    云原生環(huán)境里Nginx的故障排查思路

    本文聚焦于云原生環(huán)境下Nginx的故障排查思路。隨著云原生技術(shù)的廣泛應(yīng)用,Nginx作為常用的高性能Web服務(wù)器和反向代理服務(wù)器,在容器化和編排的環(huán)境中面臨著新的故障場(chǎng)景和挑戰(zhàn)。
    的頭像 發(fā)表于 06-17 13:53 ?456次閱讀
    <b class='flag-5'>云原生</b>環(huán)境里Nginx的故障排查思路

    智多晶LWIP網(wǎng)絡(luò)通信系統(tǒng)介紹

    在物聯(lián)網(wǎng)蓬勃興起的當(dāng)下,嵌入式設(shè)備的網(wǎng)絡(luò)通信能力如同為其插上了騰飛的翅膀,使其能夠自由穿梭于信息的浩瀚海洋。而 LWIP,宛如一位身姿矯健的輕騎兵,在資源有限的嵌入式系統(tǒng)中飛馳,輕松完成各種復(fù)雜的網(wǎng)絡(luò)通信任務(wù)。西安智多晶微電子有限公司的LWIP網(wǎng)絡(luò)通信系統(tǒng),賦予嵌入式設(shè)備強(qiáng)大的網(wǎng)絡(luò)通信能力。
    的頭像 發(fā)表于 04-10 16:27 ?1311次閱讀
    智多晶LWIP網(wǎng)絡(luò)通信系統(tǒng)介紹

    Snap Store開(kāi)發(fā)者工具圖譜:全棧云原生,一張圖解鎖Linux開(kāi)發(fā)新姿勢(shì)!

    PyCharm+Postman構(gòu)建微服務(wù),還是云原生新人嘗試Kubectl+Helm馴服K8s,SnapStore早已備好全套裝備。本文作為《UbuntuSnap》系列的第三彈
    的頭像 發(fā)表于 03-25 09:22 ?504次閱讀
    Snap Store開(kāi)發(fā)者工具圖譜:<b class='flag-5'>從</b>全棧<b class='flag-5'>到</b><b class='flag-5'>云原生</b>,一張圖解鎖Linux開(kāi)發(fā)新姿勢(shì)!

    云原生在汽車(chē)行業(yè)的優(yōu)勢(shì)

    近年來(lái),“云原生”已成為科技領(lǐng)域的高頻熱詞。企業(yè)數(shù)字化轉(zhuǎn)型智能化產(chǎn)業(yè)布局,各行各業(yè)對(duì)云原生技術(shù)的需求呈現(xiàn)爆發(fā)式增長(zhǎng),向云計(jì)算轉(zhuǎn)型已成為一大趨勢(shì)。根據(jù)Gartner的預(yù)測(cè),
    的頭像 發(fā)表于 02-21 09:20 ?1357次閱讀

    云原生AI服務(wù)怎么樣

    云原生AI服務(wù),是指采用云原生的原則和技術(shù)來(lái)構(gòu)建、部署和管理人工智能應(yīng)用及工作負(fù)載的方法和模式。那么,云原生AI服務(wù)怎么樣呢?下面,AI部落小編帶您了解。
    的頭像 發(fā)表于 01-23 10:47 ?629次閱讀

    云原生LLMOps平臺(tái)作用

    云原生LLMOps平臺(tái)是一種基于云計(jì)算基礎(chǔ)設(shè)施和開(kāi)發(fā)工具,專(zhuān)門(mén)用于構(gòu)建、部署和管理大型語(yǔ)言模型(LLM)全生命周期的平臺(tái)。以下,是對(duì)云原生LLMOps平臺(tái)作用的梳理,由AI部落小編整理。
    的頭像 發(fā)表于 01-06 10:21 ?611次閱讀

    如何選擇云原生機(jī)器學(xué)習(xí)平臺(tái)

    當(dāng)今,云原生機(jī)器學(xué)習(xí)平臺(tái)因其彈性擴(kuò)展、高效部署、低成本運(yùn)營(yíng)等優(yōu)勢(shì),逐漸成為企業(yè)構(gòu)建和部署機(jī)器學(xué)習(xí)應(yīng)用的首選。然而,市場(chǎng)上的云原生機(jī)器學(xué)習(xí)平臺(tái)種類(lèi)繁多,功能各異,如何選擇云原生機(jī)器學(xué)習(xí)平臺(tái)呢?下面,AI部落小編帶您探討。
    的頭像 發(fā)表于 12-25 11:54 ?608次閱讀

    東方通聯(lián)合openEuler社區(qū)即將開(kāi)啟云原生開(kāi)源中間件 Meetup北京站

    深入探索云原生技術(shù)的最新前沿; 剖析基礎(chǔ)軟件最“潮”趨勢(shì); 與技術(shù)大佬零距離交流; 聆聽(tīng)行業(yè)專(zhuān)家的獨(dú)家案例經(jīng)驗(yàn); 激發(fā)創(chuàng)新思維,尋找靈感火花; 更有機(jī)會(huì)獲取寶貴的實(shí)習(xí)機(jī)會(huì),以及豐富多彩的福利禮包
    的頭像 發(fā)表于 12-17 14:58 ?981次閱讀

    構(gòu)建云原生機(jī)器學(xué)習(xí)平臺(tái)流程

    構(gòu)建云原生機(jī)器學(xué)習(xí)平臺(tái)是一個(gè)復(fù)雜而系統(tǒng)的過(guò)程,涉及數(shù)據(jù)收集、處理、特征提取、模型訓(xùn)練、評(píng)估、部署和監(jiān)控等多個(gè)環(huán)節(jié)。
    的頭像 發(fā)表于 12-14 10:34 ?583次閱讀

    什么是云原生MLOps平臺(tái)

    云原生MLOps平臺(tái),是指利用云計(jì)算的基礎(chǔ)設(shè)施和開(kāi)發(fā)工具,來(lái)構(gòu)建、部署和管理機(jī)器學(xué)習(xí)模型的全生命周期的平臺(tái)。以下,是對(duì)云原生MLOps平臺(tái)的介紹,由AI部落小編整理。
    的頭像 發(fā)表于 12-12 13:13 ?719次閱讀

    梯度科技入選2024云原生企業(yè)TOP50榜單

    近日,國(guó)內(nèi)專(zhuān)業(yè)咨詢(xún)機(jī)構(gòu)DBC德本咨詢(xún)發(fā)布“2024云原生企業(yè)TOP50”榜單。梯度科技憑借自主研發(fā)的“梯度智能云平臺(tái)”入選該榜單,彰顯公司在該領(lǐng)域的行業(yè)競(jìng)爭(zhēng)力。
    的頭像 發(fā)表于 12-06 11:35 ?989次閱讀

    軟通動(dòng)力榮登2024云原生企業(yè)TOP50榜單

    近日,DBC德本咨詢(xún)發(fā)布“2024云原生企業(yè)TOP50”榜單,軟通動(dòng)力憑借自研的“天鶴云原生數(shù)據(jù)庫(kù)平臺(tái)” 榮登該榜單第8名,彰顯了公司在該領(lǐng)域的行業(yè)競(jìng)爭(zhēng)力。
    的頭像 發(fā)表于 12-04 11:27 ?738次閱讀

    云原生和數(shù)據(jù)庫(kù)哪個(gè)好一些?

    云原生和數(shù)據(jù)庫(kù)哪個(gè)好一些?云原生和數(shù)據(jù)庫(kù)各有其獨(dú)特的優(yōu)勢(shì),適用于不同的場(chǎng)景。云原生強(qiáng)調(diào)高效資源利用、快速開(kāi)發(fā)部署和高可伸縮性,適合需要高度靈活性和快速迭代的應(yīng)用。而數(shù)據(jù)庫(kù)則注重?cái)?shù)據(jù)一致性、共享和獨(dú)立性,確保數(shù)據(jù)的穩(wěn)定和安全,適用
    的頭像 發(fā)表于 11-29 10:07 ?698次閱讀

    k8s微服務(wù)架構(gòu)就是云原生嗎??jī)烧呤鞘裁搓P(guān)系

    k8s微服務(wù)架構(gòu)就是云原生嗎?K8s微服務(wù)架構(gòu)并不等同于云原生,但兩者之間存在密切的聯(lián)系。Kubernetes在云原生架構(gòu)中扮演著核心組件的角色,它簡(jiǎn)化了容器化應(yīng)用程序的管理,提供了彈性、自動(dòng)化
    的頭像 發(fā)表于 11-25 09:39 ?815次閱讀

    開(kāi)源分析和落地方案—Sentinel篇

    的解決方案,此外作為支持云原生的重要探索,還提供了GO語(yǔ)言實(shí)現(xiàn)。Sentinel目前擁有著活躍的開(kāi)源社區(qū),1.8.x版本開(kāi)始,通過(guò)深度參與SpringCloudAlibaba套件的
    的頭像 發(fā)表于 11-08 10:10 ?1687次閱讀
    開(kāi)源分析和落地方案—Sentinel篇