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', '語' và '\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 copy và append 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.Time và
reflect.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à !=),
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ụ, utf8 và
utf16 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 |
| 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 cmplx
và template.
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:
ebnfhtml†go/types
(†Các kiểu EscapeString và UnescapeString 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/vectorexp/datafmtgo/typecheckerold/regexpold/templatetry
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:
| Cũ | 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ư bytes và strings) 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 Unix
và UnixNano
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.NewReaderSize
và
bufio.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/gzip và
compress/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 Compressor và Decompressor của gói gzip
đã được đổi tên thành Writer và Reader. 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,
Unmarshal và GenerateKey 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 Marshal
và Unmarshal
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 Encoder
và Decoder 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
và
(*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/printer và
go/doc.
Các chế độ AllowIllegalChars và InsertSemis đã 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 ParseDir
và ParseExpr.
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, ValueDoc là Value, 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 Cmd và Script
đã 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.
FindTree và ScanDir được thay thế bởi
Import
và
ImportDir.
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 Handle và HandleFunc,
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
image
và
image/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.
| Cũ | 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.Opaque
và
color.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" và "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,
SetReadTimeout và SetWriteTimeout khác nhau
đã được thay thế bằng
SetDeadline,
SetReadDeadline và
SetWriteDeadline,
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
JoinGroup và LeaveGroup 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ư
ErrPermission
và
ErrNotExist.
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.Sys và
ProcessState.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.WaitStatus và
syscall.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, Perm và String.
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,
IsNotExist
và
IsPermission.
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.FileInfo
và os.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()
là
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.Cgocalls và runtime.Goroutines
đã được đổi tên thành runtime.NumCgoCall và runtime.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 Atoui và Atof32 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 template và exp/template/html đã được chuyển đến
text/template và
html/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.New và
unsafe.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/gob và thư 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.User
và net.UserPassword.
Các hàm EscapeUserinfo và UnescapeUserinfo
cũng đã biến mất.
Field RawAuthority đã bị xóa. Thông tin tương tự có sẵn
trong các field Host và User.
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 go và tà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.