自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 1.1 相比 Go1.0 有哪些值得注意的改動(dòng)?

開發(fā) 前端
Go 1.1 對(duì) Unicode 字符的處理進(jìn)行了更嚴(yán)格的約束,特別是禁止了 代理對(duì)(surrogate halves)作為獨(dú)立的?rune?值。代理對(duì)是 Unicode 標(biāo)準(zhǔn)中為了在 UTF-16 編碼里表示超過 65535 的碼點(diǎn)而設(shè)計(jì)的特殊范圍,它們本身不代表任何字符,只能成對(duì)出現(xiàn)用于組合。

Go 1.1 值得關(guān)注的改動(dòng):

  1. 字符串和 rune 字面量的定義被細(xì)化,明確排除了 Unicode 代理對(duì)(surrogate halves)作為有效的 Unicode 碼點(diǎn)。這確保了 Go 在處理 Unicode 字符時(shí)更加符合標(biāo)準(zhǔn)。
  2. Go 1.1 實(shí)現(xiàn)了 方法值(method values),這是一種綁定到特定接收器實(shí)例的函數(shù)。它與 方法表達(dá)式(method expressions)不同,后者是基于類型生成函數(shù)。這個(gè)改動(dòng)是向后兼容的。
  3. 在 64 位平臺(tái)上,int 和 uint 類型的大小從 32 位調(diào)整為 64 位。這使得在 64 位系統(tǒng)上可以分配超過 20 億個(gè)元素的切片,但也可能影響依賴 int 為 32 位假設(shè)的代碼行為。
  4. 在 64 位架構(gòu)上,最大堆內(nèi)存(heap)大小顯著增加,從之前的幾 GB 提升到了數(shù)十 GB,具體取決于系統(tǒng)。32 位架構(gòu)的堆大小保持不變。
  5. 引入了一個(gè)重要工具:競(jìng)態(tài)檢測(cè)器(race detector)。它可以幫助發(fā)現(xiàn)并發(fā)訪問同一變量(且至少一個(gè)是寫操作)導(dǎo)致的 bug,通過 go test -race 等命令啟用。
  6. go 命令進(jìn)行了一些改進(jìn)以優(yōu)化新用戶體驗(yàn),包括在找不到包時(shí)提供更詳細(xì)的錯(cuò)誤信息(包含搜索路徑),以及 go get 命令強(qiáng)制要求設(shè)置有效的 $GOPATH。
  7. go test 命令在啟用性能分析時(shí)不再刪除測(cè)試二進(jìn)制文件,方便進(jìn)行后續(xù)分析。同時(shí),新增了阻塞分析(blocking profile)功能 (-blockprofile),用于報(bào)告 goroutine 的阻塞點(diǎn)。
  8. bufio 包新增了 Scanner 類型,提供了一種更簡(jiǎn)單、更常用的方式來讀取文本輸入,例如按行或按空格分隔的單詞讀取。對(duì)于簡(jiǎn)單場(chǎng)景,它比之前的 ReadBytes, ReadString 等函數(shù)更方便。

下面是一些值得展開的討論:

Unicode 代理對(duì)的處理調(diào)整

Go 1.1 對(duì) Unicode 字符的處理進(jìn)行了更嚴(yán)格的約束,特別是禁止了 代理對(duì)(surrogate halves)作為獨(dú)立的 rune 值。代理對(duì)是 Unicode 標(biāo)準(zhǔn)中為了在 UTF-16 編碼里表示超過 65535 的碼點(diǎn)而設(shè)計(jì)的特殊范圍,它們本身不代表任何字符,只能成對(duì)出現(xiàn)用于組合。

在 Go 1.1 中,編譯器、庫和運(yùn)行時(shí)都強(qiáng)制執(zhí)行了這一約束:一個(gè)獨(dú)立的代理對(duì)碼點(diǎn)被視為非法的 rune 值,無論是在 UTF-8 編碼中,還是在單獨(dú)的 UTF-16 編碼中。當(dāng)遇到這類非法值時(shí)(例如,從 rune 轉(zhuǎn)換為 UTF-8),它會(huì)被視為編碼錯(cuò)誤,并產(chǎn)生 Unicode 替換字符 utf8.RuneError (U+FFFD)。

例如,以下代碼在 Go 1.0 和 Go 1.1 中的行為不同:

package main

import "fmt"

func main() {
    // 0xD800 是一個(gè)高位代理項(xiàng)(high surrogate)
    fmt.Printf("%+q\n", string(0xD800))
}

在 Go 1.0 中,它會(huì)打印 "\ud800"。但在 Go 1.1 中,由于 0xD800 是一個(gè)非法的獨(dú)立 rune 值,它會(huì)被替換字符替代,打印 "\ufffd"。

相應(yīng)地,包含代理對(duì) Unicode 值的 rune 和 string 常量現(xiàn)在也是非法的,例如 '\ud800' 或 "\ud800" 會(huì)導(dǎo)致編譯錯(cuò)誤。

package main

func main() {
    // Go 1.1 中編譯錯(cuò)誤: illegal rune literal
    // const r = '\ud800'  // 注意是單引號(hào)

    // Go 1.1 中編譯錯(cuò)誤: illegal rune literal
    // const s = "\ud800"  // 注意是雙引號(hào)
}

不過,如果開發(fā)者顯式地使用其 UTF-8 字節(jié)序列來創(chuàng)建字符串,例如 "\xed\xa0\x80"(這是 U+D800 的 UTF-8 編碼),這種字符串仍然可以被創(chuàng)建。但是,當(dāng)嘗試將這種包含非法 UTF-8 序列的字符串解碼為 rune 序列時(shí)(例如在 range 循環(huán)中),只會(huì)得到 utf8.RuneError。

package main

import "fmt"

func main() {
    // U+D800 的 UTF-8 編碼是 ED A0 80
    s := "\xed\xa0\x80"
    fmt.Println("String:", s) // 可以創(chuàng)建和打印

    // 遍歷時(shí),無效的 UTF-8 序列會(huì)被解碼為 RuneError (U+FFFD)
    for i, r := range s {
        fmt.Printf("Byte index %d: Rune %U (%q)\n", i, r, r)
    }
}

輸出:

String: ??? // 具體顯示取決于終端,但它包含非法序列
Byte index 0: Rune U+FFFD ('\uFFFD')
...

此外,Go 1.1 允許 Go 源文件的起始處出現(xiàn) Unicode 字節(jié)順序標(biāo)記(BOM)U+FEFF(其 UTF-8 編碼為 EF BB BF)。雖然 UTF-8 編碼本身不需要 BOM,但有些編輯器會(huì)添加它作為文件編碼的標(biāo)識(shí),此更改提升了兼容性。

總的來說,這些關(guān)于 Unicode 的改動(dòng)提高了 Go 對(duì) Unicode 標(biāo)準(zhǔn)的遵從度,使得字符處理更加健壯,對(duì)大多數(shù)程序沒有影響,但依賴舊行為處理代理對(duì)的程序需要修改。

方法值(Method Values)

Go 1.1 引入了一個(gè)新特性:方法值(method values)。方法值是一個(gè)已綁定到特定接收器值的函數(shù)。與之相對(duì)的是已有的 方法表達(dá)式(method expressions),它會(huì)從一個(gè)類型的方法生成一個(gè)函數(shù)。

方法值 (Method Value)

當(dāng)你擁有一個(gè)具體的值(接收器),并訪問它的某個(gè)方法但不立即調(diào)用它(即不加括號(hào) ()),你就得到了一個(gè)方法值。這個(gè)方法值是一個(gè)函數(shù),它內(nèi)部“記住”了那個(gè)具體的接收器。調(diào)用這個(gè)方法值就等同于在原始接收器上調(diào)用該方法。

我們來看一個(gè)例子:

package main

import (
 "fmt"
 "strings"
)

type Greeter struct {
 Name string
}

func (g Greeter) Greet() {
 fmt.Printf("Hello, %s!\n", g.Name)
}

func main() {
 g := Greeter{Name: "Alice"}

 // 獲取方法值 greetFunc
 // greetFunc 是一個(gè)函數(shù),它已經(jīng)綁定了接收器 g
 greetFunc := g.Greet

 // 調(diào)用方法值,就像調(diào)用普通函數(shù)一樣
 greetFunc() // 輸出: Hello, Alice!

 // greetFunc 的類型是 func()
 fmt.Printf("Type of greetFunc: %T\n", greetFunc) // 輸出: Type of greetFunc: func()

 // 這相當(dāng)于閉包:
 equivalentFunc := func() {
  g.Greet() // 閉包捕獲了 g
 }
 equivalentFunc() // 輸出: Hello, Alice!
}

在上面的例子中,g.Greet 就是一個(gè)方法值。它是一個(gè) func() 類型的函數(shù),調(diào)用它時(shí),Greet 方法會(huì)在 g 這個(gè)實(shí)例上執(zhí)行。

方法表達(dá)式 (Method Expression)

方法表達(dá)式則是基于 類型 而不是 實(shí)例 來獲取一個(gè)方法對(duì)應(yīng)的函數(shù)。它的形式是 TypeName.MethodName 或 (*TypeName).MethodName。這個(gè)生成的函數(shù)會(huì)將接收器作為它的 第一個(gè) 參數(shù)。

繼續(xù)使用上面的 Greeter 類型:

package main

import (
 "fmt"
 "strings"
)

type Greeter struct {
 Name string
}

func (g Greeter) Greet() {
 fmt.Printf("Hello, %s!\n", g.Name)
}

// 一個(gè)接受 name 和 age 的方法
func (g Greeter) GreetPerson(name string, age int) {
 fmt.Printf("Hello %s (%d), I'm %s.\n", name, age, g.Name)
}

func main() {
 g1 := Greeter{Name: "Alice"}
 g2 := Greeter{Name: "Bob"}

 // 獲取 Greeter 類型 Greet 方法的方法表達(dá)式
 // greetExprFunc 的類型是 func(Greeter)
 greetExprFunc := Greeter.Greet

 // 調(diào)用時(shí),需要將接收器作為第一個(gè)參數(shù)傳入
 greetExprFunc(g1) // 輸出: Hello, Alice!
 greetExprFunc(g2) // 輸出: Hello, Bob!
 fmt.Printf("Type of greetExprFunc: %T\n", greetExprFunc) // 輸出: Type of greetExprFunc: func(main.Greeter)

 // 獲取 GreetPerson 方法的方法表達(dá)式
 // greetPersonExprFunc 的類型是 func(Greeter, string, int)
 greetPersonExprFunc := Greeter.GreetPerson

 greetPersonExprFunc(g1, "Charlie", 30) // 輸出: Hello Charlie (30), I'm Alice.
 greetPersonExprFunc(g2, "David", 25)   // 輸出: Hello David (25), I'm Bob.
 fmt.Printf("Type of greetPersonExprFunc: %T\n", greetPersonExprFunc) // 輸出: Type of greetPersonExprFunc: func(main.Greeter, string, int)

}

方法表達(dá)式 Greeter.Greet 生成了一個(gè)類型為 func(Greeter) 的函數(shù)。調(diào)用它時(shí),需要顯式地傳入一個(gè) Greeter 類型的實(shí)例作為第一個(gè)參數(shù),這個(gè)實(shí)例就充當(dāng)了該次調(diào)用的接收器。同理,Greeter.GreetPerson 生成了一個(gè) func(Greeter, string, int) 類型的函數(shù)。

總結(jié)對(duì)比

  • **方法值 (instance.Method)**:綁定到 特定實(shí)例,函數(shù)簽名不包含接收器。
  • **方法表達(dá)式 (Type.Method)**:基于 類型,生成的函數(shù)簽名將接收器作為 第一個(gè)參數(shù)。

這個(gè)特性是完全向后兼容的,不會(huì)影響任何現(xiàn)有代碼的編譯和運(yùn)行。它為 Go 語言在函數(shù)式編程風(fēng)格和接口使用方面提供了更大的靈活性。

64 位平臺(tái) int 大小的變化

Go 語言規(guī)范允許 int 和 uint 類型的大小根據(jù)目標(biāo)平臺(tái)是 32 位還是 64 位來決定。在 Go 1.1 之前,所有的 Go 實(shí)現(xiàn)都將 int 和 uint 定義為 32 位。

從 Go 1.1 開始,gc(標(biāo)準(zhǔn)編譯器)和 gccgo 實(shí)現(xiàn)在 64 位平臺(tái)(如 AMD64/x86-64)上將 int 和 uint 定義為 64 位。這一變化的主要好處之一是,它使得在 64 位系統(tǒng)上可以創(chuàng)建和操作元素?cái)?shù)量超過 2^31(大約 20 億)的切片或執(zhí)行需要更大整數(shù)范圍的計(jì)算。

由于 Go 強(qiáng)制要求顯式類型轉(zhuǎn)換,不允許在不同的數(shù)字類型之間進(jìn)行隱式轉(zhuǎn)換,因此這個(gè)改變不會(huì)導(dǎo)致任何現(xiàn)有程序編譯失敗。

但是,如果程序中包含了 int 始終是 32 位的 隱式假設(shè),那么其行為可能會(huì)在 64 位平臺(tái)上發(fā)生改變。一個(gè)典型的例子涉及到從一個(gè)無符號(hào) 32 位整數(shù)轉(zhuǎn)換為 int:

package main

import "fmt"

func main() {
 // x 的值是 0xffffffff (即 2^32 - 1)
 x := ^uint32(0)
 fmt.Printf("x (uint32): %x\n", x)

 // 將 x 轉(zhuǎn)換為 int
 i := int(x)

 // 在 32 位系統(tǒng)上:
 // int 是 32 位,int(0xffffffff) 會(huì)被解釋為 -1 (二進(jìn)制補(bǔ)碼表示)
 // 輸出: i (int): -1 (on 32-bit systems)

 // 在 64 位系統(tǒng)上 (Go 1.1+):
 // int 是 64 位,int(0xffffffff) 會(huì)被零擴(kuò)展為 64 位,值仍為 0xffffffff
 // 輸出: i (int): 4294967295 (on 64-bit systems)
 fmt.Printf("i (int): %d\n", i)
}

在 32 位系統(tǒng)上,int 和 uint32 大小相同,將 0xffffffff 轉(zhuǎn)換為 int 時(shí),其位模式保持不變,根據(jù) int(有符號(hào)類型)的解釋,這個(gè)位模式代表 -1。

但在 Go 1.1 及以后版本的 64 位系統(tǒng)上,int 是 64 位。當(dāng)將 32 位的 x (值為 0xffffffff) 轉(zhuǎn)換為 64 位的 int 時(shí),會(huì)進(jìn)行零擴(kuò)展(因?yàn)樵搭愋褪菬o符號(hào)的),結(jié)果是 64 位的 0x00000000ffffffff,其十進(jìn)制值是 4294967295。

如果你的代碼需要確保無論在哪種平臺(tái),都執(zhí)行 32 位的符號(hào)擴(kuò)展(即將 0xffffffff 轉(zhuǎn)換為 -1),應(yīng)該先顯式地將值轉(zhuǎn)換為 int32,再轉(zhuǎn)換為 int:

package main

import "fmt"

func main() {
 x := ^uint32(0) // x is 0xffffffff

 // 先轉(zhuǎn)換為 int32,再轉(zhuǎn)換為 int
 // int32(x) 的值是 -1
 // int(-1) 在 32 位和 64 位 int 上都是 -1
 i := int(int32(x))

 fmt.Printf("Portable i (int): %d\n", i) // 在所有平臺(tái)上都輸出 -1
}

通過 int32(x),我們將 0xffffffff 強(qiáng)制解釋為 32 位有符號(hào)整數(shù),得到 -1。然后 int(-1) 在任何位數(shù)的 int 上結(jié)果都是 -1。

這個(gè)改動(dòng)對(duì)大部分程序是透明的,但開發(fā)者應(yīng)檢查代碼中是否存在對(duì) int 位寬的隱藏假設(shè),尤其是在進(jìn)行位運(yùn)算或與底層系統(tǒng)、特定數(shù)據(jù)格式交互時(shí)。

go 命令的改進(jìn)

Go 1.1 對(duì) go 命令行工具進(jìn)行了一些旨在改善新用戶體驗(yàn)和規(guī)范項(xiàng)目管理的改動(dòng)。

1. 更詳細(xì)的包未找到錯(cuò)誤信息

當(dāng)使用 go build, go test 或 go run 等命令時(shí),如果無法定位所需的包,go 命令現(xiàn)在會(huì)提供更詳細(xì)的錯(cuò)誤輸出。錯(cuò)誤信息會(huì)包含它嘗試搜索包的具體路徑列表,這些路徑基于 $GOROOT 和 $GOPATH 環(huán)境變量。

例如,如果嘗試構(gòu)建一個(gè)不存在的包 foo/quxx:

$ go build foo/quxx
can't load package: package foo/quxx: cannot find package "foo/quxx" in any of:
        /usr/local/go/src/pkg/foo/quxx (from $GOROOT) # 假設(shè) $GOROOT 是 /usr/local/go
        /home/user/go/src/foo/quxx (from $GOPATH)     # 假設(shè) $GOPATH 是 /home/user/go

這個(gè)改進(jìn)讓開發(fā)者能更快地診斷出是 $GOPATH 設(shè)置不正確、包未下載還是路徑拼寫錯(cuò)誤等問題。

2. go get 強(qiáng)制要求 $GOPATH

go get 命令用于下載和安裝包及其依賴。在 Go 1.1 中,go get 不再允許在沒有設(shè)置有效 $GOPATH 的情況下運(yùn)行,并且不再隱式地將 $GOROOT 作為下載目標(biāo)?,F(xiàn)在,必須設(shè)置一個(gè)有效的 $GOPATH 環(huán)境變量,go get 會(huì)將下載的源碼放在 $GOPATH/src 目錄下。

如果 $GOPATH 未設(shè)置:

$ GOPATH= go get example.com/some/package
package example.com/some/package: cannot download, $GOPATH not set. For more details see: go help gopath

3. go get 禁止 $GOPATH 與 $GOROOT 相同

作為上一條規(guī)則的延伸,Go 1.1 還禁止將 $GOPATH 設(shè)置為與 $GOROOT 相同的值。$GOROOT 指向 Go 的安裝目錄,包含標(biāo)準(zhǔn)庫源碼,而 $GOPATH 指向用戶的工作區(qū),包含第三方庫和用戶自己的項(xiàng)目代碼。將兩者混用會(huì)導(dǎo)致管理混亂。

如果 $GOPATH 被設(shè)置為 $GOROOT:

$ export GOPATH=$GOROOT # 假設(shè) GOROOT 是 /usr/local/go
$ go get example.com/some/package
warning: GOPATH set to GOROOT (/usr/local/go) has no effect
package example.com/some/package: cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath

這些對(duì) go 命令的改動(dòng),特別是圍繞 $GOPATH 的調(diào)整,旨在引導(dǎo)開發(fā)者從一開始就采用標(biāo)準(zhǔn)的 Go 工作區(qū)布局,這對(duì)于管理依賴和項(xiàng)目結(jié)構(gòu)至關(guān)重要,尤其是在 Go Modules 出現(xiàn)之前。

責(zé)任編輯:武曉燕 來源: Piper蛋窩
相關(guān)推薦

2025-04-14 00:00:00

2025-04-18 08:07:12

2025-04-14 08:06:04

2025-04-15 08:00:53

2025-04-17 08:00:48

2025-04-25 08:01:12

Go應(yīng)用程序部署

2025-04-28 08:00:56

2025-04-29 08:03:18

2025-04-21 00:05:00

2025-04-21 08:00:56

2025-04-22 08:02:23

2025-04-23 08:02:40

2025-04-21 00:00:00

Go 開發(fā)Go 語言Go 1.9

2025-04-14 00:00:04

2025-04-24 09:01:46

2025-04-27 08:00:35

2025-04-27 00:00:01

Go 1.16Go 1.15接口

2025-04-30 09:02:46

2025-04-10 08:03:18

Go 1rune? 類型類型推斷

2010-07-12 10:48:21

SQL Server數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)