Ghi chú phát hành Go 1

Giới thiệu về Go 1

Go phiên bản 1, gọi tắt là Go 1, định nghĩa một ngôn ngữ và một bộ thư viện cốt lõi cung cấp nền tảng ổn định để xây dựng các sản phẩm, dự án và ấn phẩm đáng tin cậy.

Động lực chính của Go 1 là sự ổn định cho người dùng. Mọi người có thể viết chương trình Go và kỳ vọng rằng chúng sẽ tiếp tục biên dịch và chạy mà không cần thay đổi, trong nhiều năm, kể cả trong các môi trường production như Google App Engine. Tương tự, mọi người có thể viết sách về Go, nêu rõ phiên bản Go mà cuốn sách mô tả, và số phiên bản đó vẫn còn có ý nghĩa sau nhiều năm.

Mã nguồn biên dịch được trong Go 1 sẽ, với một vài ngoại lệ, tiếp tục biên dịch và chạy suốt vòng đời của phiên bản đó, ngay cả khi chúng tôi phát hành cập nhật và sửa lỗi như Go phiên bản 1.1, 1.2 và tiếp theo. Ngoài những sửa lỗi nghiêm trọng, các thay đổi đối với ngôn ngữ và thư viện trong các bản phát hành tiếp theo của Go 1 có thể bổ sung chức năng nhưng sẽ không làm hỏng các chương trình Go 1 hiện có. Tài liệu tương thích Go 1 giải thích chi tiết hơn về các hướng dẫn tương thích.

Go 1 là biểu hiện của Go như hiện đang được sử dụng, không phải là việc xem xét lại toàn bộ ngôn ngữ. Chúng tôi tránh thiết kế các tính năng mới mà thay vào đó tập trung vào việc khắc phục các vấn đề, sự không nhất quán và cải thiện tính di động. Có một số thay đổi đối với ngôn ngữ và các gói Go mà chúng tôi đã cân nhắc trong một thời gian và đã làm mẫu thử nhưng chưa phát hành, chủ yếu vì chúng đáng kể và không tương thích ngược. Go 1 là cơ hội để đưa chúng ra, điều này có lợi cho dài hạn, nhưng cũng có nghĩa là Go 1 giới thiệu sự không tương thích với các chương trình cũ. May mắn thay, công cụ go fix có thể tự động hóa phần lớn công việc cần thiết để đưa các chương trình lên chuẩn Go 1.

Tài liệu này phác thảo những thay đổi chính trong Go 1 sẽ ảnh hưởng đến các lập trình viên đang cập nhật mã nguồn hiện có; điểm tham chiếu của nó là bản phát hành trước đó, r60 (được gắn thẻ là r60.3). Nó cũng giải thích cách cập nhật mã nguồn từ r60 để chạy trên Go 1.

Thay đổi về ngôn ngữ

Append

Hàm variadic tiền khai báo append giúp dễ dàng mở rộng một slice bằng cách thêm các phần tử vào cuối. Một cách dùng phổ biến là thêm byte vào cuối một byte slice khi tạo đầu ra. Tuy nhiên, append không cung cấp cách để nối một chuỗi vào một []byte, đây là một trường hợp phổ biến khác.

    greeting := []byte{}
    greeting = append(greeting, []byte("hello ")...)

Tương tự với tính năng tương tự của copy, Go 1 cho phép một chuỗi được nối (theo từng byte) trực tiếp vào một byte slice, giảm ma sát giữa chuỗi và byte slice. Phép chuyển đổi không còn cần thiết nữa:

    greeting = append(greeting, "world"...)

Cập nhật: Đây là tính năng mới, vì vậy mã nguồn hiện có không cần thay đổi.

Close

Hàm tiền khai báo close cung cấp cơ chế để một bên gửi báo hiệu rằng sẽ không còn gửi thêm giá trị nào nữa. Nó quan trọng đối với việc triển khai các vòng lặp for range trên channel và hữu ích trong các tình huống khác. Một phần do thiết kế và một phần do điều kiện race có thể xảy ra, nó chỉ được dùng bởi goroutine gửi trên channel, không phải goroutine nhận dữ liệu. Tuy nhiên, trước Go 1 không có kiểm tra lúc biên dịch rằng close đang được dùng đúng cách.

Để thu hẹp khoảng cách này, ít nhất là một phần, Go 1 không cho phép close trên các channel chỉ nhận. Cố gắng đóng một channel như vậy là lỗi lúc biên dịch.

    var c chan int
    var csend chan<- int = c
    var crecv <-chan int = c
    close(c)     // legal
    close(csend) // legal
    close(crecv) // illegal

Cập nhật: Mã nguồn hiện có cố gắng đóng một channel chỉ nhận đã là lỗi ngay cả trước Go 1 và cần được sửa. Trình biên dịch sẽ từ chối mã nguồn như vậy.

Composite literals

Trong Go 1, một composite literal của kiểu mảng, slice hoặc map có thể bỏ qua đặc tả kiểu cho các bộ khởi tạo phần tử nếu chúng là kiểu con trỏ. Cả bốn khởi tạo trong ví dụ này đều hợp lệ; cái cuối cùng không hợp lệ trước Go 1.

    type Date struct {
        month string
        day   int
    }
    // Struct values, fully qualified; always legal.
    holiday1 := []Date{
        Date{"Feb", 14},
        Date{"Nov", 11},
        Date{"Dec", 25},
    }
    // Struct values, type name elided; always legal.
    holiday2 := []Date{
        {"Feb", 14},
        {"Nov", 11},
        {"Dec", 25},
    }
    // Pointers, fully qualified, always legal.
    holiday3 := []*Date{
        &Date{"Feb", 14},
        &Date{"Nov", 11},
        &Date{"Dec", 25},
    }
    // Pointers, type name elided; legal in Go 1.
    holiday4 := []*Date{
        {"Feb", 14},
        {"Nov", 11},
        {"Dec", 25},
    }

Cập nhật: Thay đổi này không ảnh hưởng đến mã nguồn hiện có, nhưng lệnh gofmt -s áp dụng lên mã nguồn hiện có sẽ, trong số các việc khác, bỏ qua các kiểu phần tử tường minh ở bất cứ đâu được phép.

Goroutine trong init

Ngôn ngữ cũ định nghĩa rằng các câu lệnh go được thực thi trong quá trình khởi tạo tạo ra goroutine nhưng chúng không bắt đầu chạy cho đến khi quá trình khởi tạo của toàn bộ chương trình hoàn tất. Điều này tạo ra sự vụng về ở nhiều nơi và, trên thực tế, hạn chế tính hữu ích của cấu trúc init: nếu một gói khác có thể sử dụng thư viện trong quá trình khởi tạo, thư viện buộc phải tránh dùng goroutine. Thiết kế này được thực hiện vì lý do đơn giản và an toàn nhưng, khi sự tin tưởng của chúng tôi vào ngôn ngữ tăng lên, điều đó có vẻ không cần thiết. Chạy goroutine trong quá trình khởi tạo không phức tạp hay không an toàn hơn chạy chúng trong quá trình thực thi bình thường.

Trong Go 1, mã nguồn sử dụng goroutine có thể được gọi từ các hàm init và các biểu thức khởi tạo toàn cục mà không gây ra deadlock.

var PackageGlobal int

func init() {
    c := make(chan int)
    go initializationFunction(c)
    PackageGlobal = <-c
}

Cập nhật: Đây là tính năng mới, vì vậy mã nguồn hiện có không cần thay đổi, mặc dù có thể mã nguồn phụ thuộc vào việc goroutine không khởi động trước main sẽ bị hỏng. Không có mã nguồn như vậy trong kho lưu trữ chuẩn.

Kiểu rune

Đặc tả ngôn ngữ cho phép kiểu int rộng 32 hoặc 64 bit, nhưng các triển khai hiện tại đặt int thành 32 bit ngay cả trên các nền tảng 64 bit. Sẽ tốt hơn nếu int là 64 bit trên các nền tảng 64 bit. (Có những hệ quả quan trọng đối với việc đánh chỉ số các slice lớn.) Tuy nhiên, thay đổi này sẽ lãng phí không gian khi xử lý các ký tự Unicode với ngôn ngữ cũ vì kiểu int cũng được dùng để giữ các điểm mã Unicode: mỗi điểm mã sẽ lãng phí thêm 32 bit lưu trữ nếu int tăng từ 32 bit lên 64.

Để làm cho việc chuyển sang int 64 bit khả thi, Go 1 giới thiệu một kiểu cơ bản mới, rune, để biểu diễn các điểm mã Unicode riêng lẻ. Nó là bí danh cho int32, tương tự như byte là bí danh cho uint8.

Các ký tự literal như 'a', '語''\u0345' bây giờ có kiểu mặc định là rune, tương tự như 1.0 có kiểu mặc định là float64. Do đó, một biến được khởi tạo bằng một hằng ký tự sẽ có kiểu rune trừ khi được chỉ định khác.

Các thư viện đã được cập nhật để dùng rune thay vì int khi phù hợp. Ví dụ, các hàm unicode.ToLower và các hàm liên quan bây giờ nhận và trả về kiểu rune.

    delta := 'δ' // delta has type rune.
    var DELTA rune
    DELTA = unicode.ToUpper(delta)
    epsilon := unicode.ToLower(DELTA + 1)
    if epsilon != 'δ'+1 {
        log.Fatal("inconsistent casing for Greek")
    }

Cập nhật: Hầu hết mã nguồn sẽ không bị ảnh hưởng vì suy luận kiểu từ các bộ khởi tạo := đưa vào kiểu mới một cách im lặng, và nó lan truyền từ đó. Một số mã nguồn có thể gặp lỗi kiểu mà một phép chuyển đổi đơn giản sẽ giải quyết.

Kiểu error

Go 1 giới thiệu kiểu built-in mới, error, có định nghĩa như sau:

    type error interface {
        Error() string
    }

Vì hệ quả của kiểu này đều nằm trong thư viện gói, nó được thảo luận bên dưới.

Xóa khỏi map

Trong ngôn ngữ cũ, để xóa mục có khóa k từ map m, người ta viết câu lệnh,

    m[k] = value, false

Cú pháp này là một trường hợp đặc biệt kỳ lạ, phép gán hai-vào-một duy nhất. Nó yêu cầu truyền một giá trị (thường bị bỏ qua) được đánh giá nhưng bị loại bỏ, cộng với một boolean gần như luôn là hằng số false. Nó hoạt động nhưng kỳ lạ và là điểm tranh cãi.

Trong Go 1, cú pháp đó đã biến mất; thay vào đó có một hàm built-in mới, delete. Lệnh gọi

    delete(m, k)

sẽ xóa mục map được lấy bởi biểu thức m[k]. Không có giá trị trả về. Xóa một mục không tồn tại là no-op.

Cập nhật: Chạy go fix sẽ chuyển đổi các biểu thức dạng m[k] = value, false thành delete(m, k) khi rõ ràng là giá trị bị bỏ qua có thể được loại bỏ một cách an toàn khỏi chương trình và false tham chiếu đến hằng boolean được định nghĩa sẵn. Công cụ fix sẽ đánh dấu các cách dùng khác của cú pháp này để lập trình viên kiểm tra.

Duyệt map

Đặc tả ngôn ngữ cũ không định nghĩa thứ tự duyệt đối với map, và trên thực tế nó khác nhau trên các nền tảng phần cứng. Điều này làm cho các test duyệt qua map dễ bị hỏng và không di động, với tính chất khó chịu là một test có thể luôn vượt qua trên một máy nhưng bị hỏng trên máy khác.

Trong Go 1, thứ tự các phần tử được thăm khi duyệt qua một map bằng câu lệnh for range được định nghĩa là không thể đoán trước, ngay cả khi cùng một vòng lặp được chạy nhiều lần với cùng một map. Mã nguồn không nên giả định rằng các phần tử được thăm theo bất kỳ thứ tự cụ thể nào.

Thay đổi này có nghĩa là mã nguồn phụ thuộc vào thứ tự duyệt rất có thể sẽ bị hỏng sớm và được sửa trước khi trở thành vấn đề. Quan trọng không kém, nó cho phép triển khai map đảm bảo cân bằng map tốt hơn ngay cả khi chương trình sử dụng vòng lặp range để chọn một phần tử từ map.

    m := map[string]int{"Sunday": 0, "Monday": 1}
    for name, value := range m {
        // This loop should not assume Sunday will be visited first.
        f(name, value)
    }

Cập nhật: Đây là một thay đổi mà các công cụ không thể giúp đỡ. Hầu hết mã nguồn hiện có sẽ không bị ảnh hưởng, nhưng một số chương trình có thể bị hỏng hoặc hoạt động sai; chúng tôi khuyến nghị kiểm tra thủ công tất cả các câu lệnh range trên map để xác minh chúng không phụ thuộc vào thứ tự duyệt. Có một vài ví dụ như vậy trong kho lưu trữ chuẩn; chúng đã được sửa. Lưu ý rằng việc phụ thuộc vào thứ tự duyệt đã là sai ngay từ đầu, vì thứ tự đó không được chỉ định. Thay đổi này quy định hóa tính không thể đoán trước.

Phép gán nhiều giá trị

Đặc tả ngôn ngữ từ lâu đã đảm bảo rằng trong các phép gán tất cả các biểu thức vế phải đều được đánh giá trước khi bất kỳ biểu thức vế trái nào được gán. Để đảm bảo hành vi có thể dự đoán, Go 1 tinh chỉnh thêm đặc tả.

Nếu vế trái của câu lệnh gán chứa các biểu thức yêu cầu đánh giá, chẳng hạn như các lệnh gọi hàm hoặc thao tác đánh chỉ số mảng, chúng đều sẽ được thực hiện theo quy tắc từ trái sang phải thông thường trước khi bất kỳ biến nào được gán giá trị của chúng. Sau khi mọi thứ được đánh giá, các phép gán thực tế diễn ra theo thứ tự từ trái sang phải.

Các ví dụ này minh họa hành vi.

    sa := []int{1, 2, 3}
    i := 0
    i, sa[i] = 1, 2 // sets i = 1, sa[0] = 2

    sb := []int{1, 2, 3}
    j := 0
    sb[j], j = 2, 1 // sets sb[0] = 2, j = 1

    sc := []int{1, 2, 3}
    sc[0], sc[0] = 1, 2 // sets sc[0] = 1, then sc[0] = 2 (so sc[0] = 2 at end)

Cập nhật: Đây là một thay đổi mà các công cụ không thể giúp đỡ, nhưng khả năng hỏng là thấp. Không có mã nguồn nào trong kho lưu trữ chuẩn bị hỏng bởi thay đổi này, và mã nguồn phụ thuộc vào hành vi không được chỉ định trước đây đã sai rồi.

Return và biến bị che khuất

Một lỗi phổ biến là dùng return (không có đối số) sau khi gán cho một biến có cùng tên với biến kết quả nhưng không phải là cùng biến. Tình huống này được gọi là shadowing: biến kết quả đã bị che khuất bởi biến khác có cùng tên được khai báo trong phạm vi bên trong.

Trong các hàm có giá trị trả về được đặt tên, trình biên dịch Go 1 không cho phép câu lệnh return không có đối số nếu bất kỳ giá trị trả về được đặt tên nào bị che khuất tại điểm của câu lệnh return. (Nó không phải là một phần của đặc tả, vì đây là một lĩnh vực chúng tôi vẫn đang khám phá; tình huống tương tự như trình biên dịch từ chối các hàm không kết thúc bằng câu lệnh return tường minh.)

Hàm này trả về ngầm một giá trị trả về bị che khuất và sẽ bị trình biên dịch từ chối:

func Bug() (i, j, k int) {
    for i = 0; i < 5; i++ {
        for j := 0; j < 5; j++ { // Redeclares j.
            k += i * j
            if k > 100 {
                return // Rejected: j is shadowed here.
            }
        }
    }
    return // OK: j is not shadowed here.
}

Cập nhật: Mã nguồn che khuất các giá trị trả về theo cách này sẽ bị trình biên dịch từ chối và cần được sửa thủ công. Một vài trường hợp xuất hiện trong kho lưu trữ chuẩn hầu hết là lỗi.

Sao chép struct có trường không xuất

Ngôn ngữ cũ không cho phép một gói tạo bản sao của một giá trị struct chứa các trường không xuất thuộc về gói khác. Tuy nhiên, có một ngoại lệ bắt buộc cho một method receiver; ngoài ra, các triển khai của copyappend chưa bao giờ tuân thủ hạn chế này.

Go 1 sẽ cho phép các gói sao chép các giá trị struct chứa các trường không xuất từ các gói khác. Ngoài việc giải quyết sự không nhất quán, thay đổi này cho phép một loại API mới: một gói có thể trả về một giá trị mờ đục mà không cần dùng đến con trỏ hoặc interface. Các triển khai mới của time.Timereflect.Value là ví dụ về các kiểu tận dụng thuộc tính mới này.

Ví dụ, nếu gói p bao gồm các định nghĩa,

    type Struct struct {
        Public int
        secret int
    }
    func NewStruct(a int) Struct {  // Lưu ý: không phải con trỏ.
        return Struct{a, f(a)}
    }
    func (s Struct) String() string {
        return fmt.Sprintf("{%d (secret %d)}", s.Public, s.secret)
    }

một gói import p có thể gán và sao chép các giá trị kiểu p.Struct tùy ý. Phía sau, các trường không xuất sẽ được gán và sao chép giống như khi chúng được xuất, nhưng mã nguồn phía khách hàng sẽ không bao giờ biết về chúng. Mã nguồn

    import "p"

    myStruct := p.NewStruct(23)
    copyOfMyStruct := myStruct
    fmt.Println(myStruct, copyOfMyStruct)

sẽ cho thấy rằng trường secret của struct đã được sao chép sang giá trị mới.

Cập nhật: Đây là tính năng mới, vì vậy mã nguồn hiện có không cần thay đổi.

So sánh bằng

Trước Go 1, ngôn ngữ không định nghĩa so sánh bằng trên các giá trị struct và mảng. Điều này có nghĩa là, trong số các thứ khác, struct và mảng không thể được dùng làm khóa map. Mặt khác, Go định nghĩa so sánh bằng trên các giá trị hàm và map. So sánh bằng hàm là vấn đề khi có closure (khi nào hai closure bằng nhau?) trong khi so sánh bằng map so sánh các con trỏ, không phải nội dung của map, điều này thường không phải là điều người dùng muốn.

Go 1 giải quyết những vấn đề này. Đầu tiên, struct và mảng có thể được so sánh bằng và bất bằng (==!=), và do đó có thể được dùng làm khóa map, miễn là chúng được cấu thành từ các phần tử mà so sánh bằng cũng được định nghĩa, sử dụng so sánh từng phần tử.

    type Day struct {
        long  string
        short string
    }
    Christmas := Day{"Christmas", "XMas"}
    Thanksgiving := Day{"Thanksgiving", "Turkey"}
    holiday := map[Day]bool{
        Christmas:    true,
        Thanksgiving: true,
    }
    fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])

Thứ hai, Go 1 loại bỏ định nghĩa so sánh bằng cho các giá trị hàm, ngoại trừ so sánh với nil. Cuối cùng, so sánh bằng map cũng biến mất, ngoại trừ so sánh với nil.

Lưu ý rằng so sánh bằng vẫn chưa được định nghĩa cho slice, vì phép tính nhìn chung là không khả thi. Cũng lưu ý rằng các toán tử so sánh có thứ tự (< <= > >=) vẫn chưa được định nghĩa cho struct và mảng.

Cập nhật: So sánh bằng struct và mảng là tính năng mới, vì vậy mã nguồn hiện có không cần thay đổi. Mã nguồn hiện có phụ thuộc vào so sánh bằng hàm hoặc map sẽ bị trình biên dịch từ chối và cần được sửa thủ công. Ít chương trình sẽ bị ảnh hưởng, nhưng việc sửa có thể yêu cầu một số thiết kế lại.

Phân cấp gói

Go 1 giải quyết nhiều thiếu sót trong thư viện chuẩn cũ và dọn dẹp một số gói, làm cho chúng nhất quán nội bộ hơn và di động hơn.

Phần này mô tả cách các gói đã được sắp xếp lại trong Go 1. Một số đã di chuyển, một số đã được đổi tên, một số đã bị xóa. Các gói mới được mô tả trong các phần sau.

Phân cấp gói

Go 1 có phân cấp gói được sắp xếp lại để nhóm các mục liên quan vào các thư mục con. Ví dụ, utf8utf16 bây giờ chiếm các thư mục con của unicode. Ngoài ra, một số gói đã được chuyển vào các kho phụ của code.google.com/p/go trong khi một số khác đã bị xóa hoàn toàn.

Đường dẫn cũ Đường dẫn mới

asn1 encoding/asn1
csv encoding/csv
gob encoding/gob
json encoding/json
xml encoding/xml

exp/template/html html/template

big math/big
cmath math/cmplx
rand math/rand

http net/http
http/cgi net/http/cgi
http/fcgi net/http/fcgi
http/httptest net/http/httptest
http/pprof net/http/pprof
mail net/mail
rpc net/rpc
rpc/jsonrpc net/rpc/jsonrpc
smtp net/smtp
url net/url

exec os/exec

scanner text/scanner
tabwriter text/tabwriter
template text/template
template/parse text/template/parse

utf8 unicode/utf8
utf16 unicode/utf16

Lưu ý rằng tên gói cho các gói cmath cũ và exp/template/html đã thay đổi thành cmplxtemplate.

Cập nhật: Chạy go fix sẽ cập nhật tất cả các import và đổi tên gói cho các gói vẫn còn trong kho lưu trữ chuẩn. Các chương trình import các gói không còn trong kho lưu trữ chuẩn sẽ cần được chỉnh sửa thủ công.

Cây gói exp

Vì chúng không được tiêu chuẩn hóa, các gói trong thư mục exp sẽ không có trong các bản phân phối phát hành Go 1 chuẩn, mặc dù chúng sẽ có dưới dạng mã nguồn trong kho lưu trữ cho các nhà phát triển muốn dùng chúng.

Một số gói đã chuyển vào exp tại thời điểm phát hành Go 1:

  • ebnf
  • html
  • go/types

(Các kiểu EscapeStringUnescapeString vẫn còn trong gói html.)

Tất cả các gói này đều có sẵn dưới các tên giống nhau, với tiền tố exp/: exp/ebnf v.v.

Ngoài ra, kiểu utf8.String đã được chuyển vào gói riêng của nó, exp/utf8string.

Cuối cùng, lệnh gotype hiện nằm trong exp/gotype, trong khi ebnflint hiện nằm trong exp/ebnflint. Nếu chúng được cài đặt, chúng hiện nằm trong $GOROOT/bin/tool.

Cập nhật: Mã nguồn sử dụng các gói trong exp sẽ cần được cập nhật thủ công, hoặc được biên dịch từ một cài đặt có sẵn exp. Công cụ go fix hoặc trình biên dịch sẽ phàn nàn về những cách dùng như vậy.

Cây gói old

Vì chúng không được khuyến nghị, các gói trong thư mục old sẽ không có trong các bản phân phối phát hành Go 1 chuẩn, mặc dù chúng sẽ có dưới dạng mã nguồn cho các nhà phát triển muốn dùng chúng.

Các gói ở vị trí mới của chúng là:

  • old/netchan

Cập nhật: Mã nguồn sử dụng các gói hiện nằm trong old sẽ cần được cập nhật thủ công, hoặc được biên dịch từ một cài đặt có sẵn old. Công cụ go fix sẽ cảnh báo về những cách dùng như vậy.

Các gói đã bị xóa

Go 1 xóa hoàn toàn một số gói:

  • container/vector
  • exp/datafmt
  • go/typechecker
  • old/regexp
  • old/template
  • try

và cả lệnh gotry.

Cập nhật: Mã nguồn sử dụng container/vector nên được cập nhật để dùng slice trực tiếp. Xem Go Language Community Wiki để biết một số gợi ý. Mã nguồn sử dụng các gói khác (gần như sẽ bằng không) sẽ cần được xem xét lại.

Các gói chuyển sang kho phụ

Go 1 đã chuyển một số gói vào các kho lưu trữ khác, thường là kho phụ của kho lưu trữ Go chính. Bảng này liệt kê các đường dẫn import cũ và mới:

Mới

crypto/bcrypt code.google.com/p/go.crypto/bcrypt
crypto/blowfish code.google.com/p/go.crypto/blowfish
crypto/cast5 code.google.com/p/go.crypto/cast5
crypto/md4 code.google.com/p/go.crypto/md4
crypto/ocsp code.google.com/p/go.crypto/ocsp
crypto/openpgp code.google.com/p/go.crypto/openpgp
crypto/openpgp/armor code.google.com/p/go.crypto/openpgp/armor
crypto/openpgp/elgamal code.google.com/p/go.crypto/openpgp/elgamal
crypto/openpgp/errors code.google.com/p/go.crypto/openpgp/errors
crypto/openpgp/packet code.google.com/p/go.crypto/openpgp/packet
crypto/openpgp/s2k code.google.com/p/go.crypto/openpgp/s2k
crypto/ripemd160 code.google.com/p/go.crypto/ripemd160
crypto/twofish code.google.com/p/go.crypto/twofish
crypto/xtea code.google.com/p/go.crypto/xtea
exp/ssh code.google.com/p/go.crypto/ssh

image/bmp code.google.com/p/go.image/bmp
image/tiff code.google.com/p/go.image/tiff

net/dict code.google.com/p/go.net/dict
net/websocket code.google.com/p/go.net/websocket
exp/spdy code.google.com/p/go.net/spdy

encoding/git85 code.google.com/p/go.codereview/git85
patch code.google.com/p/go.codereview/patch

exp/wingui code.google.com/p/gowingui

Cập nhật: Chạy go fix sẽ cập nhật các import của các gói này để dùng các đường dẫn import mới. Các cài đặt phụ thuộc vào các gói này sẽ cần cài đặt chúng bằng lệnh go get.

Thay đổi lớn đối với thư viện

Phần này mô tả những thay đổi đáng kể đối với các thư viện cốt lõi, những thay đổi ảnh hưởng đến nhiều chương trình nhất.

Kiểu error và gói errors

Việc đặt os.Error trong gói os chủ yếu mang tính lịch sử: các lỗi xuất hiện lần đầu khi triển khai gói os, và chúng có vẻ liên quan đến hệ thống vào lúc đó. Kể từ đó, rõ ràng là các lỗi mang tính cơ bản hơn hệ điều hành. Ví dụ, sẽ tốt nếu dùng Errors trong các gói mà os phụ thuộc vào, như syscall. Ngoài ra, việc có Error trong os tạo ra nhiều dependency vào os mà lẽ ra không cần thiết.

Go 1 giải quyết những vấn đề này bằng cách giới thiệu kiểu interface built-in error và gói errors riêng biệt (tương tự như bytesstrings) chứa các hàm tiện ích. Nó thay thế os.NewError bằng errors.New, đặt lỗi vào vị trí trung tâm hơn trong môi trường.

Để phương thức String được sử dụng rộng rãi không vô tình thỏa mãn interface error, interface error thay vào đó dùng tên Error cho phương thức đó:

    type error interface {
        Error() string
    }

Thư viện fmt tự động gọi Error, cũng như đã làm với String, để in các giá trị lỗi dễ dàng.

type SyntaxError struct {
    File    string
    Line    int
    Message string
}

func (se *SyntaxError) Error() string {
    return fmt.Sprintf("%s:%d: %s", se.File, se.Line, se.Message)
}

Tất cả các gói chuẩn đã được cập nhật để dùng interface mới; os.Error cũ đã biến mất.

Một gói mới, errors, chứa hàm

func New(text string) error

để chuyển đổi một chuỗi thành lỗi. Nó thay thế os.NewError cũ.

    var ErrSyntax = errors.New("syntax error")

Cập nhật: Chạy go fix sẽ cập nhật hầu hết mã nguồn bị ảnh hưởng bởi thay đổi. Mã nguồn định nghĩa các kiểu lỗi với phương thức String sẽ cần được cập nhật thủ công để đổi tên phương thức thành Error.

Lỗi system call

Gói syscall cũ, có trước os.Error (và hầu hết mọi thứ khác), trả về lỗi dưới dạng giá trị int. Đến lượt mình, gói os chuyển tiếp nhiều lỗi trong số này, chẳng hạn như EINVAL, nhưng dùng một tập hợp lỗi khác nhau trên mỗi nền tảng. Hành vi này thật khó chịu và không di động.

Trong Go 1, gói syscall thay vào đó trả về một error cho lỗi system call. Trên Unix, việc triển khai được thực hiện bằng kiểu syscall.Errno thỏa mãn error và thay thế os.Errno cũ.

Các thay đổi ảnh hưởng đến os.EINVAL và các hằng liên quan được mô tả ở nơi khác.

Cập nhật: Chạy go fix sẽ cập nhật hầu hết mã nguồn bị ảnh hưởng bởi thay đổi. Dù vậy, hầu hết mã nguồn nên dùng gói os thay vì syscall và do đó sẽ không bị ảnh hưởng.

Time

Thời gian luôn là thách thức để hỗ trợ tốt trong ngôn ngữ lập trình. Gói time cũ của Go có đơn vị int64, không có an toàn kiểu thực sự, và không phân biệt giữa thời điểm tuyệt đối và khoảng thời gian.

Một trong những thay đổi toàn diện nhất trong thư viện Go 1 là một thiết kế lại hoàn toàn của gói time. Thay vì một số nguyên nanosecond dưới dạng int64, và một kiểu *time.Time riêng biệt để xử lý các đơn vị của con người như giờ và năm, bây giờ có hai kiểu cơ bản: time.Time (một giá trị, vì vậy * đã biến mất), biểu diễn một thời điểm; và time.Duration, biểu diễn một khoảng thời gian. Cả hai đều có độ phân giải nanosecond. Một Time có thể biểu diễn bất kỳ thời điểm nào trong quá khứ xa xôi và tương lai xa, trong khi một Duration có thể trải dài cộng hoặc trừ khoảng 290 năm. Có các phương thức trên các kiểu này, cộng với một số hằng khoảng thời gian được xác định trước hữu ích như time.Second.

Trong số các phương thức mới có những thứ như Time.Add, cộng một Duration vào một Time, và Time.Sub, trừ hai Time để tạo ra một Duration.

Thay đổi ngữ nghĩa quan trọng nhất là epoch Unix (ngày 1 tháng 1 năm 1970) bây giờ chỉ liên quan đến những hàm và phương thức đề cập đến Unix: time.Unix và các phương thức UnixUnixNano của kiểu Time. Cụ thể, time.Now trả về giá trị time.Time thay vì, trong API cũ, một số nguyên đếm nanosecond kể từ epoch Unix.

// sleepUntil sleeps until the specified time. It returns immediately if it's too late.
func sleepUntil(wakeup time.Time) {
    now := time.Now() // A Time.
    if !wakeup.After(now) {
        return
    }
    delta := wakeup.Sub(now) // A Duration.
    fmt.Printf("Sleeping for %.3fs\n", delta.Seconds())
    time.Sleep(delta)
}

Các kiểu, phương thức và hằng số mới đã được lan truyền qua tất cả các gói chuẩn sử dụng thời gian, chẳng hạn như os và biểu diễn của nó về dấu thời gian tệp.

Cập nhật: Công cụ go fix sẽ cập nhật nhiều cách dùng của gói time cũ để dùng các kiểu và phương thức mới, mặc dù nó không thay thế các giá trị như 1e9 biểu diễn nanosecond mỗi giây. Ngoài ra, vì có thay đổi kiểu trong một số giá trị xuất hiện, một số biểu thức được công cụ fix viết lại có thể yêu cầu chỉnh sửa thủ công thêm; trong những trường hợp như vậy, phần viết lại sẽ bao gồm hàm hoặc phương thức đúng cho chức năng cũ, nhưng có thể có kiểu sai hoặc yêu cầu phân tích thêm.

Thay đổi nhỏ đối với thư viện

Phần này mô tả các thay đổi nhỏ hơn, chẳng hạn như những thay đổi đối với các gói ít được dùng hơn hoặc ảnh hưởng đến ít chương trình ngoài nhu cầu chạy go fix. Danh mục này bao gồm các gói mới trong Go 1. Tổng thể chúng cải thiện tính di động, quy chuẩn hóa hành vi, và làm cho các interface hiện đại hơn và mang phong cách Go hơn.

Gói archive/zip

Trong Go 1, *zip.Writer không còn có phương thức Write. Sự hiện diện của nó là một sai lầm.

Cập nhật: Mã nguồn bị ảnh hưởng ít ỏi sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Gói bufio

Trong Go 1, các hàm bufio.NewReaderSizebufio.NewWriterSize không còn trả về lỗi với kích thước không hợp lệ. Nếu đối số kích thước quá nhỏ hoặc không hợp lệ, nó được điều chỉnh.

Cập nhật: Chạy go fix sẽ cập nhật các lệnh gọi gán lỗi cho _. Các lệnh gọi không được sửa sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Các gói compress/flate, compress/gzip và compress/zlib

Trong Go 1, các hàm NewWriterXxx trong compress/flate, compress/gzipcompress/zlib đều trả về (*Writer, error) nếu chúng nhận mức nén, và *Writer nếu không. Các kiểu CompressorDecompressor của gói gzip đã được đổi tên thành WriterReader. Kiểu WrongValueError của gói flate đã bị xóa.

Cập nhật Chạy go fix sẽ cập nhật các tên cũ và các lệnh gọi gán lỗi cho _. Các lệnh gọi không được sửa sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Các gói crypto/aes và crypto/des

Trong Go 1, phương thức Reset đã bị xóa. Go không đảm bảo rằng bộ nhớ không được sao chép và do đó phương thức này gây nhầm lẫn.

Các kiểu cụ thể cho cipher *aes.Cipher, *des.Cipher, và *des.TripleDESCipher đã bị xóa để ủng hộ cipher.Block.

Cập nhật: Xóa các lệnh gọi Reset. Thay thế các cách dùng kiểu cipher cụ thể bằng cipher.Block.

Gói crypto/elliptic

Trong Go 1, elliptic.Curve đã được tạo thành một interface để cho phép các triển khai thay thế. Các tham số curve đã được chuyển sang cấu trúc elliptic.CurveParams.

Cập nhật: Người dùng hiện tại của *elliptic.Curve sẽ cần thay đổi thành chỉ elliptic.Curve. Các lệnh gọi đến Marshal, UnmarshalGenerateKey bây giờ là các hàm trong crypto/elliptic nhận một elliptic.Curve làm đối số đầu tiên của chúng.

Gói crypto/hmac

Trong Go 1, các hàm cụ thể cho hash, chẳng hạn như hmac.NewMD5, đã bị xóa khỏi crypto/hmac. Thay vào đó, hmac.New nhận một hàm trả về hash.Hash, chẳng hạn như md5.New.

Cập nhật: Chạy go fix sẽ thực hiện các thay đổi cần thiết.

Gói crypto/x509

Trong Go 1, hàm CreateCertificate và phương thức CreateCRL trong crypto/x509 đã được sửa đổi để nhận một interface{} ở nơi trước đây chúng nhận *rsa.PublicKey hoặc *rsa.PrivateKey. Điều này sẽ cho phép các thuật toán khóa công khai khác được triển khai trong tương lai.

Cập nhật: Không cần thay đổi nào.

Gói encoding/binary

Trong Go 1, hàm binary.TotalSize đã được thay thế bằng Size, nhận một đối số interface{} thay vì một reflect.Value.

Cập nhật: Mã nguồn bị ảnh hưởng ít ỏi sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Gói encoding/xml

Trong Go 1, gói xml đã được đưa gần hơn với thiết kế của các gói marshaling khác như encoding/gob.

Kiểu Parser cũ được đổi tên thành Decoder và có phương thức Decode mới. Một kiểu Encoder cũng đã được giới thiệu.

Các hàm MarshalUnmarshal bây giờ làm việc với các giá trị []byte. Để làm việc với các stream, dùng các kiểu EncoderDecoder mới.

Khi marshaling hoặc unmarshaling các giá trị, định dạng của các flag được hỗ trợ trong field tag đã thay đổi để gần hơn với gói json (`xml:"name,flag"`). Việc khớp giữa field tag, tên field và tên thuộc tính XML và phần tử bây giờ phân biệt chữ hoa chữ thường. Field tag XMLName, nếu có, cũng phải khớp với tên của phần tử XML đang được marshal.

Cập nhật: Chạy go fix sẽ cập nhật hầu hết cách dùng của gói ngoại trừ một số lệnh gọi đến Unmarshal. Cần cẩn thận đặc biệt với field tag, vì công cụ fix sẽ không cập nhật chúng và nếu không được sửa thủ công chúng sẽ hoạt động sai trong im lặng ở một số trường hợp. Ví dụ, cũ "attr" bây giờ được viết ",attr" trong khi "attr" thuần túy vẫn hợp lệ nhưng có ý nghĩa khác.

Gói expvar

Trong Go 1, hàm RemoveAll đã bị xóa. Hàm Iter và phương thức Iter trên *Map đã được thay thế bởi Do(*Map).Do.

Cập nhật: Hầu hết mã nguồn dùng expvar sẽ không cần thay đổi. Mã nguồn hiếm dùng Iter có thể được cập nhật để truyền một closure cho Do để đạt được hiệu ứng tương tự.

Gói flag

Trong Go 1, interface flag.Value đã thay đổi một chút. Phương thức Set bây giờ trả về một error thay vì một bool để biểu thị thành công hay thất bại.

Ngoài ra còn có một loại flag mới, Duration, để hỗ trợ các giá trị đối số chỉ định khoảng thời gian. Các giá trị cho các flag như vậy phải được đưa ra kèm đơn vị, giống như time.Duration định dạng chúng: 10s, 1h30m, v.v.

var timeout = flag.Duration("timeout", 30*time.Second, "how long to wait for completion")

Cập nhật: Các chương trình triển khai flag của riêng chúng sẽ cần sửa thủ công nhỏ để cập nhật phương thức Set của chúng. Flag Duration là mới và không ảnh hưởng đến mã nguồn hiện có.

Các gói go/*

Một số gói trong go có API được sửa đổi nhẹ.

Kiểu Mode cụ thể đã được giới thiệu cho các flag chế độ cấu hình trong các gói go/scanner, go/parser, go/printergo/doc.

Các chế độ AllowIllegalCharsInsertSemis đã bị xóa khỏi gói go/scanner. Chúng chủ yếu hữu ích cho việc quét văn bản khác với các file mã nguồn Go. Thay vào đó, gói text/scanner nên được dùng cho mục đích đó.

ErrorHandler được cung cấp cho phương thức Init của scanner bây giờ chỉ là một hàm đơn giản thay vì một interface. Kiểu ErrorVector đã bị xóa để ủng hộ kiểu ErrorList (đã tồn tại), và các phương thức ErrorVector đã được di chuyển sang. Thay vì nhúng một ErrorVector vào một client của scanner, bây giờ một client nên duy trì một ErrorList.

Tập hợp các hàm phân tích cú pháp được cung cấp bởi gói go/parser đã được thu gọn thành hàm phân tích cú pháp chính ParseFile, và một vài hàm tiện ích ParseDirParseExpr.

Gói go/printer hỗ trợ thêm chế độ cấu hình SourcePos; nếu được đặt, printer sẽ phát ra các comment //line sao cho đầu ra được tạo chứa thông tin vị trí mã nguồn gốc. Kiểu mới CommentedNode có thể được dùng để cung cấp các comment liên kết với một ast.Node tùy ý (cho đến nay chỉ ast.File mang thông tin comment).

Tên kiểu của gói go/doc đã được đơn giản hóa bằng cách xóa hậu tố Doc: PackageDoc bây giờ là Package, ValueDocValue, v.v. Ngoài ra, tất cả các kiểu bây giờ đều nhất quán có field Name (hoặc Names, trong trường hợp kiểu Value) và Type.Factories đã trở thành Type.Funcs. Thay vì gọi doc.NewPackageDoc(pkg, importpath), tài liệu cho một gói được tạo với:

    doc.New(pkg, importpath, mode)

trong đó tham số mode mới chỉ định chế độ hoạt động: nếu được đặt thành AllDecls, tất cả các khai báo (không chỉ các khai báo được xuất) được xem xét. Hàm NewFileDoc đã bị xóa, và hàm CommentText đã trở thành phương thức Text của ast.CommentGroup.

Trong gói go/token, phương thức token.FileSet Files (trước đây trả về một channel của *token.File) đã được thay thế bằng iterator Iterate nhận một đối số hàm thay thế.

Trong gói go/build, API gần như đã được thay thế hoàn toàn. Gói vẫn tính toán thông tin gói Go nhưng nó không chạy build: các kiểu CmdScript đã biến mất. (Để build mã nguồn, hãy dùng lệnh go mới thay thế.) Kiểu DirInfo bây giờ được đặt tên là Package. FindTreeScanDir được thay thế bởi ImportImportDir.

Cập nhật: Mã nguồn dùng các gói trong go sẽ phải được cập nhật thủ công; trình biên dịch sẽ từ chối các cách dùng không chính xác. Các template được sử dụng kết hợp với bất kỳ kiểu go/doc nào có thể cần sửa thủ công; các field được đổi tên sẽ dẫn đến lỗi thời gian chạy.

Gói hash

Trong Go 1, định nghĩa của hash.Hash bao gồm một phương thức mới, BlockSize. Phương thức mới này được dùng chủ yếu trong các thư viện mã hóa.

Phương thức Sum của interface hash.Hash bây giờ nhận một đối số []byte, mà giá trị hash sẽ được nối thêm vào. Hành vi trước đây có thể được tái tạo bằng cách thêm đối số nil vào lệnh gọi.

Cập nhật: Các triển khai hiện có của hash.Hash sẽ cần thêm phương thức BlockSize. Các hash xử lý đầu vào một byte tại một thời điểm có thể triển khai BlockSize để trả về 1. Chạy go fix sẽ cập nhật các lệnh gọi đến phương thức Sum của các triển khai khác nhau của hash.Hash.

Cập nhật: Vì chức năng của gói là mới, không cần cập nhật nào.

Gói http

Trong Go 1, gói http được tái cấu trúc, đặt một số tiện ích vào thư mục con httputil. Những phần này chỉ hiếm khi cần bởi các client HTTP. Các mục bị ảnh hưởng là:

  • ClientConn
  • DumpRequest
  • DumpRequestOut
  • DumpResponse
  • NewChunkedReader
  • NewChunkedWriter
  • NewClientConn
  • NewProxyClientConn
  • NewServerConn
  • NewSingleHostReverseProxy
  • ReverseProxy
  • ServerConn

Field Request.RawURL đã bị xóa; nó là một tạo phẩm lịch sử.

Các hàm HandleHandleFunc, và các phương thức cùng tên của ServeMux, bây giờ gây panic nếu cố gắng đăng ký cùng một pattern hai lần.

Cập nhật: Chạy go fix sẽ cập nhật một số chương trình bị ảnh hưởng ngoại trừ các cách dùng RawURL, phải được sửa thủ công.

Gói image

Gói image đã có một số thay đổi nhỏ, sắp xếp lại và đổi tên.

Hầu hết mã xử lý màu đã được chuyển vào gói riêng của nó, image/color. Đối với các phần tử đã di chuyển, xuất hiện một sự đối xứng; ví dụ, mỗi pixel của image.RGBA là một color.RGBA.

Gói image/ycbcr cũ đã được hợp nhất, với một số đổi tên, vào các gói imageimage/color.

Kiểu image.ColorImage cũ vẫn còn trong gói image nhưng đã được đổi tên thành image.Uniform, trong khi image.Tiled đã bị xóa.

Bảng này liệt kê các đổi tên.

Mới

image.Color color.Color
image.ColorModel color.Model
image.ColorModelFunc color.ModelFunc
image.PalettedColorModel color.Palette

image.RGBAColor color.RGBA
image.RGBA64Color color.RGBA64
image.NRGBAColor color.NRGBA
image.NRGBA64Color color.NRGBA64
image.AlphaColor color.Alpha
image.Alpha16Color color.Alpha16
image.GrayColor color.Gray
image.Gray16Color color.Gray16

image.RGBAColorModel color.RGBAModel
image.RGBA64ColorModel color.RGBA64Model
image.NRGBAColorModel color.NRGBAModel
image.NRGBA64ColorModel color.NRGBA64Model
image.AlphaColorModel color.AlphaModel
image.Alpha16ColorModel color.Alpha16Model
image.GrayColorModel color.GrayModel
image.Gray16ColorModel color.Gray16Model

ycbcr.RGBToYCbCr color.RGBToYCbCr
ycbcr.YCbCrToRGB color.YCbCrToRGB
ycbcr.YCbCrColorModel color.YCbCrModel
ycbcr.YCbCrColor color.YCbCr
ycbcr.YCbCr image.YCbCr

ycbcr.SubsampleRatio444 image.YCbCrSubsampleRatio444
ycbcr.SubsampleRatio422 image.YCbCrSubsampleRatio422
ycbcr.SubsampleRatio420 image.YCbCrSubsampleRatio420

image.ColorImage image.Uniform

Các hàm New của gói image (NewRGBA, NewRGBA64, v.v.) nhận một image.Rectangle làm đối số thay vì bốn số nguyên.

Cuối cùng, có các biến color.Color được định nghĩa sẵn mới color.Black, color.White, color.Opaquecolor.Transparent.

Cập nhật: Chạy go fix sẽ cập nhật hầu hết mã nguồn bị ảnh hưởng bởi thay đổi.

Gói log/syslog

Trong Go 1, hàm syslog.NewLogger trả về cả một lỗi lẫn một log.Logger.

Cập nhật: Mã nguồn bị ảnh hưởng ít ỏi sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Gói mime

Trong Go 1, hàm FormatMediaType của gói mime đã được đơn giản hóa để làm cho nó nhất quán với ParseMediaType. Bây giờ nó nhận "text/html" thay vì "text""html".

Cập nhật: Mã nguồn bị ảnh hưởng ít ỏi sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Gói net

Trong Go 1, các phương thức SetTimeout, SetReadTimeoutSetWriteTimeout khác nhau đã được thay thế bằng SetDeadline, SetReadDeadlineSetWriteDeadline, tương ứng. Thay vì nhận một giá trị timeout tính bằng nanosecond áp dụng cho bất kỳ hoạt động nào trên kết nối, các phương thức mới đặt một deadline tuyệt đối (dưới dạng giá trị time.Time) sau đó đọc và ghi sẽ timeout và không còn block.

Ngoài ra còn có các hàm mới net.DialTimeout để đơn giản hóa việc timeout khi kết nối đến một địa chỉ mạng và net.ListenMulticastUDP để cho phép UDP multicast lắng nghe đồng thời qua nhiều listener. Hàm net.ListenMulticastUDP thay thế các phương thức JoinGroupLeaveGroup cũ.

Cập nhật: Mã nguồn dùng các phương thức cũ sẽ không biên dịch được và phải được cập nhật thủ công. Sự thay đổi ngữ nghĩa làm cho công cụ fix khó cập nhật tự động.

Gói os

Hàm Time đã bị xóa; người gọi nên dùng kiểu Time từ gói time.

Hàm Exec đã bị xóa; người gọi nên dùng Exec từ gói syscall, khi có sẵn.

Hàm ShellExpand đã được đổi tên thành ExpandEnv.

Hàm NewFile bây giờ nhận một uintptr fd, thay vì một int. Phương thức Fd trên các file bây giờ cũng trả về một uintptr.

Không còn các hằng lỗi như EINVAL trong gói os, vì tập hợp các giá trị khác nhau với hệ điều hành cơ bản. Có các hàm di động mới như IsPermission để kiểm tra các thuộc tính lỗi phổ biến, cộng với một vài giá trị lỗi mới với tên mang phong cách Go hơn, chẳng hạn như ErrPermissionErrNotExist.

Hàm Getenverror đã bị xóa. Để phân biệt giữa một biến môi trường không tồn tại và một chuỗi rỗng, dùng os.Environ hoặc syscall.Getenv.

Phương thức Process.Wait đã bỏ đối số tùy chọn của nó và các hằng liên quan đã biến mất khỏi gói. Ngoài ra, hàm Wait đã biến mất; chỉ phương thức của kiểu Process vẫn còn.

Kiểu Waitmsg được trả về bởi Process.Wait đã được thay thế bằng kiểu ProcessState di động hơn với các phương thức accessor để lấy thông tin về process. Do thay đổi đối với Wait, giá trị ProcessState luôn mô tả một process đã thoát. Các mối lo ngại về tính di động đã đơn giản hóa interface theo những cách khác, nhưng các giá trị được trả về bởi ProcessState.SysProcessState.SysUsage có thể được type-assert sang các cấu trúc dữ liệu cụ thể cho hệ thống bên dưới như syscall.WaitStatussyscall.Rusage trên Unix.

Cập nhật: Chạy go fix sẽ bỏ đối số zero vào Process.Wait. Tất cả các thay đổi khác sẽ bị bắt bởi trình biên dịch và phải được cập nhật thủ công.

Kiểu os.FileInfo

Go 1 định nghĩa lại kiểu os.FileInfo, thay đổi nó từ struct thành interface:

    type FileInfo interface {
        Name() string       // tên cơ sở của file
        Size() int64        // độ dài tính bằng byte
        Mode() FileMode     // các bit chế độ file
        ModTime() time.Time // thời gian sửa đổi
        IsDir() bool        // viết tắt cho Mode().IsDir()
        Sys() interface{}   // nguồn dữ liệu cơ bản (có thể trả về nil)
    }

Thông tin chế độ file đã được chuyển vào một kiểu con gọi là os.FileMode, một kiểu số nguyên đơn giản với các phương thức IsDir, PermString.

Các chi tiết cụ thể của hệ thống về chế độ file và thuộc tính như (trên Unix) i-number đã bị xóa hoàn toàn khỏi FileInfo. Thay vào đó, gói os của mỗi hệ điều hành cung cấp một triển khai của interface FileInfo, có phương thức Sys trả về biểu diễn metadata file cụ thể cho hệ thống. Ví dụ, để khám phá i-number của một file trên hệ thống Unix, giải nén FileInfo như thế này:

    fi, err := os.Stat("hello.go")
    if err != nil {
        log.Fatal(err)
    }
    // Kiểm tra đây là file Unix.
    unixStat, ok := fi.Sys().(*syscall.Stat_t)
    if !ok {
        log.Fatal("hello.go: not a Unix file")
    }
    fmt.Printf("file i-number: %d\n", unixStat.Ino)

Giả sử (điều này không khôn ngoan) rằng "hello.go" là một file Unix, biểu thức i-number có thể được rút gọn thành

    fi.Sys().(*syscall.Stat_t).Ino

Đại đa số cách dùng FileInfo chỉ cần các phương thức của interface chuẩn.

Gói os không còn chứa các wrapper cho các lỗi POSIX như ENOENT. Đối với một vài chương trình cần xác minh các điều kiện lỗi cụ thể, bây giờ có các hàm boolean IsExist, IsNotExistIsPermission.

    f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
    if os.IsExist(err) {
        log.Printf("%s already exists", name)
    }

Cập nhật: Chạy go fix sẽ cập nhật mã nguồn dùng phiên bản tương đương cũ của API os.FileInfoos.FileMode hiện tại. Mã nguồn cần chi tiết file cụ thể cho hệ thống sẽ cần được cập nhật thủ công. Mã nguồn dùng các giá trị lỗi POSIX cũ từ gói os sẽ không biên dịch được và cũng cần được cập nhật thủ công.

Gói os/signal

Gói os/signal trong Go 1 thay thế hàm Incoming, trả về một channel nhận tất cả các tín hiệu đến, bằng hàm có chọn lọc Notify, yêu cầu gửi các tín hiệu cụ thể trên một channel hiện có.

Cập nhật: Mã nguồn phải được cập nhật thủ công. Bản dịch nguyên văn của

c := signal.Incoming()

c := make(chan os.Signal, 1)
signal.Notify(c) // yêu cầu tất cả các tín hiệu

nhưng hầu hết mã nguồn nên liệt kê các tín hiệu cụ thể mà chúng muốn xử lý:

c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)

Gói path/filepath

Trong Go 1, hàm Walk của gói path/filepath đã được thay đổi để nhận giá trị hàm kiểu WalkFunc thay vì giá trị interface Visitor. WalkFunc hợp nhất việc xử lý cả file và thư mục.

    type WalkFunc func(path string, info os.FileInfo, err error) error

Hàm WalkFunc sẽ được gọi ngay cả đối với các file hoặc thư mục không thể mở được; trong những trường hợp như vậy, đối số lỗi sẽ mô tả sự thất bại. Nếu nội dung của một thư mục cần bị bỏ qua, hàm nên trả về giá trị filepath.SkipDir

    markFn := func(path string, info os.FileInfo, err error) error {
        if path == "pictures" { // Will skip walking of directory pictures and its contents.
            return filepath.SkipDir
        }
        if err != nil {
            return err
        }
        log.Println(path)
        return nil
    }
    err := filepath.Walk(".", markFn)
    if err != nil {
        log.Fatal(err)
    }

Cập nhật: Thay đổi đơn giản hóa hầu hết mã nguồn nhưng có hệ quả tinh tế, vì vậy các chương trình bị ảnh hưởng sẽ cần được cập nhật thủ công. Trình biên dịch sẽ bắt mã nguồn dùng interface cũ.

Gói regexp

Gói regexp đã được viết lại. Nó có cùng interface nhưng đặc tả của các biểu thức chính quy mà nó hỗ trợ đã thay đổi từ dạng “egrep” cũ sang dạng của RE2.

Cập nhật: Mã nguồn dùng gói nên kiểm tra thủ công các biểu thức chính quy của nó.

Gói runtime

Trong Go 1, phần lớn API được xuất bởi gói runtime đã bị xóa để ủng hộ chức năng được cung cấp bởi các gói khác. Mã nguồn dùng interface runtime.Type hoặc các triển khai kiểu cụ thể của nó nên bây giờ dùng gói reflect. Mã nguồn dùng runtime.Semacquire hoặc runtime.Semrelease nên dùng channel hoặc các trừu tượng trong gói sync. Các hàm runtime.Alloc, runtime.Free, và runtime.Lookup, một API không an toàn được tạo ra để gỡ lỗi bộ cấp phát bộ nhớ, không có sự thay thế.

Trước đây, runtime.MemStats là một biến toàn cục chứa thống kê về cấp phát bộ nhớ, và các lệnh gọi đến runtime.UpdateMemStats đảm bảo rằng nó được cập nhật. Trong Go 1, runtime.MemStats là một kiểu struct, và mã nguồn nên dùng runtime.ReadMemStats để lấy thống kê hiện tại.

Gói thêm một hàm mới, runtime.NumCPU, trả về số lượng CPU có sẵn để thực thi song song, theo báo cáo của nhân hệ điều hành. Giá trị của nó có thể thông báo cho việc đặt GOMAXPROCS. Các hàm runtime.Cgocallsruntime.Goroutines đã được đổi tên thành runtime.NumCgoCallruntime.NumGoroutine.

Cập nhật: Chạy go fix sẽ cập nhật mã nguồn cho các đổi tên hàm. Mã nguồn khác sẽ cần được cập nhật thủ công.

Gói strconv

Trong Go 1, gói strconv đã được làm lại đáng kể để làm cho nó mang phong cách Go hơn và ít phong cách C hơn, mặc dù Atoi vẫn còn (nó tương tự như int(ParseInt(x, 10, 0)), cũng như Itoa(x) (FormatInt(int64(x), 10)). Ngoài ra còn có các biến thể mới của một số hàm nối vào byte slice thay vì trả về chuỗi, để cho phép kiểm soát việc cấp phát.

Bảng này tóm tắt các đổi tên; xem tài liệu gói để biết chi tiết đầy đủ.

Lệnh gọi cũ Lệnh gọi mới

Atob(x) ParseBool(x)

Atof32(x) ParseFloat(x, 32)§
Atof64(x) ParseFloat(x, 64)
AtofN(x, n) ParseFloat(x, n)

Atoi(x) Atoi(x)
Atoi(x) ParseInt(x, 10, 0)§
Atoi64(x) ParseInt(x, 10, 64)

Atoui(x) ParseUint(x, 10, 0)§
Atoui64(x) ParseUint(x, 10, 64)

Btoi64(x, b) ParseInt(x, b, 64)
Btoui64(x, b) ParseUint(x, b, 64)

Btoa(x) FormatBool(x)

Ftoa32(x, f, p) FormatFloat(float64(x), f, p, 32)
Ftoa64(x, f, p) FormatFloat(x, f, p, 64)
FtoaN(x, f, p, n) FormatFloat(x, f, p, n)

Itoa(x) Itoa(x)
Itoa(x) FormatInt(int64(x), 10)
Itoa64(x) FormatInt(x, 10)

Itob(x, b) FormatInt(int64(x), b)
Itob64(x, b) FormatInt(x, b)

Uitoa(x) FormatUint(uint64(x), 10)
Uitoa64(x) FormatUint(x, 10)

Uitob(x, b) FormatUint(uint64(x), b)
Uitob64(x, b) FormatUint(x, b)

Cập nhật: Chạy go fix sẽ cập nhật hầu hết mã nguồn bị ảnh hưởng bởi thay đổi.
§ Atoi vẫn còn nhưng AtouiAtof32 thì không, vì vậy chúng có thể yêu cầu một phép ép kiểu phải được thêm thủ công; công cụ go fix sẽ cảnh báo về điều đó.

Các gói template

Các gói templateexp/template/html đã được chuyển đến text/templatehtml/template. Quan trọng hơn, interface với các gói này đã được đơn giản hóa. Ngôn ngữ template vẫn như cũ, nhưng khái niệm “template set” đã biến mất và các hàm và phương thức của các gói đã thay đổi theo đó, thường bằng cách loại bỏ.

Thay vì các tập hợp, một đối tượng Template có thể chứa nhiều định nghĩa template được đặt tên, trên thực tế xây dựng các không gian tên cho việc gọi template. Một template có thể gọi bất kỳ template nào khác được liên kết với nó, nhưng chỉ những template được liên kết với nó. Cách đơn giản nhất để liên kết các template là phân tích cú pháp chúng cùng nhau, điều gì đó được thực hiện dễ hơn với cấu trúc mới của các gói.

Cập nhật: Các import sẽ được cập nhật bởi công cụ fix. Các cách dùng template đơn sẽ phần lớn không bị ảnh hưởng. Mã nguồn dùng nhiều template kết hợp sẽ cần được cập nhật thủ công. Các ví dụ trong tài liệu cho text/template có thể cung cấp hướng dẫn.

Gói testing

Gói testing có một kiểu, B, được truyền làm đối số cho các hàm benchmark. Trong Go 1, B có các phương thức mới, tương tự như của T, cho phép ghi nhật ký và báo cáo lỗi.

func BenchmarkSprintf(b *testing.B) {
    // Verify correctness before running benchmark.
    b.StopTimer()
    got := fmt.Sprintf("%x", 23)
    const expect = "17"
    if expect != got {
        b.Fatalf("expected %q; got %q", expect, got)
    }
    b.StartTimer()
    for i := 0; i < b.N; i++ {
        fmt.Sprintf("%x", 23)
    }
}

Cập nhật: Mã nguồn hiện có không bị ảnh hưởng, mặc dù các benchmark dùng println hoặc panic nên được cập nhật để dùng các phương thức mới.

Gói testing/script

Gói testing/script đã bị xóa. Nó là một mảnh vụn không cần thiết.

Cập nhật: Không có mã nguồn nào có khả năng bị ảnh hưởng.

Gói unsafe

Trong Go 1, các hàm unsafe.Typeof, unsafe.Reflect, unsafe.Unreflect, unsafe.Newunsafe.NewArray đã bị xóa; chúng trùng lặp chức năng an toàn hơn được cung cấp bởi gói reflect.

Cập nhật: Mã nguồn dùng các hàm này phải được viết lại để dùng gói reflect. Các thay đổi đối với encoding/gobthư viện protocol buffer có thể hữu ích như các ví dụ.

Gói url

Trong Go 1, một số field từ kiểu url.URL đã bị xóa hoặc thay thế.

Phương thức String bây giờ xây dựng lại một chuỗi URL được mã hóa một cách có thể dự đoán bằng cách dùng tất cả các field của URL khi cần thiết. Chuỗi kết quả cũng sẽ không còn có mật khẩu được escape.

Field Raw đã bị xóa. Trong hầu hết các trường hợp, phương thức String có thể được dùng thay thế.

Field RawUserinfo cũ được thay thế bởi field User kiểu *net.Userinfo. Các giá trị kiểu này có thể được tạo ra bằng các hàm mới net.Usernet.UserPassword. Các hàm EscapeUserinfoUnescapeUserinfo cũng đã biến mất.

Field RawAuthority đã bị xóa. Thông tin tương tự có sẵn trong các field HostUser.

Field RawPath và phương thức EncodedPath đã bị xóa. Thông tin đường dẫn trong các URL có gốc (với dấu gạch chéo sau schema) bây giờ chỉ có sẵn ở dạng đã giải mã trong field Path. Đôi khi, dữ liệu được mã hóa có thể cần thiết để lấy thông tin bị mất trong quá trình giải mã. Những trường hợp này phải được xử lý bằng cách truy cập dữ liệu mà URL được xây dựng từ đó.

Các URL có đường dẫn không có gốc, chẳng hạn như "mailto:dev@golang.org?subject=Hi", cũng được xử lý khác đi. Field boolean OpaquePath đã bị xóa và một field chuỗi Opaque mới được giới thiệu để giữ đường dẫn được mã hóa cho các URL như vậy. Trong Go 1, URL được trích dẫn phân tích cú pháp thành:

    URL{
        Scheme: "mailto",
        Opaque: "dev@golang.org",
        RawQuery: "subject=Hi",
    }

Một phương thức mới RequestURI đã được thêm vào URL.

Hàm ParseWithReference đã được đổi tên thành ParseWithFragment.

Cập nhật: Mã nguồn dùng các field cũ sẽ không biên dịch được và phải được cập nhật thủ công. Các thay đổi ngữ nghĩa làm cho công cụ fix khó cập nhật tự động.

Lệnh go

Go 1 giới thiệu lệnh go, một công cụ để tìm nạp, build và cài đặt các gói và lệnh Go. Lệnh go loại bỏ makefile, thay vào đó dùng mã nguồn Go để tìm các dependency và xác định các điều kiện build. Hầu hết các chương trình Go hiện có sẽ không còn cần makefile để được build.

Xem Cách viết mã Go để có phần giới thiệu về lệnh gotài liệu lệnh go để biết chi tiết đầy đủ.

Cập nhật: Các dự án phụ thuộc vào cơ sở hạ tầng build dựa trên makefile cũ của dự án Go (Make.pkg, Make.cmd, v.v.) nên chuyển sang dùng lệnh go để build mã Go và, nếu cần thiết, viết lại makefile của chúng để thực hiện bất kỳ nhiệm vụ build phụ trợ nào.

Lệnh cgo

Trong Go 1, lệnh cgo dùng một file _cgo_export.h khác, được tạo ra cho các gói có chứa các dòng //export. File _cgo_export.h bây giờ bắt đầu bằng comment preamble C, để các định nghĩa hàm được xuất có thể dùng các kiểu được định nghĩa ở đó. Điều này có tác dụng biên dịch preamble nhiều lần, vì vậy một gói dùng //export không được đặt các định nghĩa hàm hoặc khởi tạo biến trong preamble C.

Các bản phát hành đóng gói

Một trong những thay đổi quan trọng nhất liên quan đến Go 1 là sự có sẵn của các bản phân phối có thể tải xuống được đóng gói sẵn. Chúng có sẵn cho nhiều kết hợp kiến trúc và hệ điều hành (bao gồm cả Windows) và danh sách sẽ phát triển. Chi tiết cài đặt được mô tả trên trang Bắt đầu, trong khi các bản phân phối chính chúng được liệt kê trên trang tải xuống.