12/08/2018, 15:22

Một số kiến thức căn bản về golang

Ngôn ngữ lập trình Go là ngôn ngữ nguồn mở của Google, giúp bạn dễ dàng tạo được phần mềm đơn giản, ổn định và hiệu quả. Go là một phần trong dòng ngôn ngữ lập trình của nhóm Communicationg Sequential Processes của Tony Hoare đưa ra, ngoài Go còn có Occam, Erlang, Newsqueak và Limbo. Dưới đây là ...

Ngôn ngữ lập trình Go là ngôn ngữ nguồn mở của Google, giúp bạn dễ dàng tạo được phần mềm đơn giản, ổn định và hiệu quả. Go là một phần trong dòng ngôn ngữ lập trình của nhóm Communicationg Sequential Processes của Tony Hoare đưa ra, ngoài Go còn có Occam, Erlang, Newsqueak và Limbo. Dưới đây là những tính năng khác biệt mà Go có được so với các ngôn ngữ lập trình phổ biến khác, trong đó có tính năng cực kỳ hữu dụng là concurrency. Hiện dự án này có hơn 500 cộng tác viên, do ông Rob Pike (là kỹ sư giỏi tại Google) quản lý, người từng làm việc tại Bell Labs trong đội Unix và đồng tác giả của Plan 9 và Inferno.

Slide

Ngôn ngữ Go triển khai ý tưởng về mảng (array) với slide. Một slide trỏ tới một mảng giá trị và có một độ dài. []T là một slice với các yếu tố của loại T. Trong ví dụ hình trên, chúng ta sử dụng slide of slide của byte chưa được gán để chứa giá trị pixel trong một ảnh mà chúng ta tự tạo ra. Với package main, chương trình bắt đầu chạy. Khai báo import là một bản mở rộng của khai báo include của C và C++; ở đây chúng ta đang lấy file pic từ repo Mercurial. Cú pháp := khai báo và khởi tạo một biến, và trình biên dịch đưa ra một type dữ liệu bất cứ khi nào có thể. Cũng vậy, make được dùng để tạo ra slide và vài loại dữ liệu khác. Vòng lặp for..range tương đương với vòng lặp for..in của C#.

Map

Khai báo Go map gán khoá key đến giá trị. Với slide, bạn có thể tạo một map bằng make, không phải new. Trong ví dụ trên, chúng ta đang gán khoá string bằng giá trị số nguyên (integer). Dưới đây là ví dụ về chèn, cập nhật, xoá và thử các thành phần map. Hình trên sẽ xuất ra:

The value: 42 
The value: 48 The value: 0 
The value: 0 
Present? false 

Struct và method Ngôn ngữ Go không có lớp (class) nhưng lại có struct, là một chuỗi các yếu tố được đặt tên, gọi là trường (field), mỗi trường có một tên và một loại. Một method là một hàm với một đầu nhận (receiver). Một khai báo method kết nối một bộ nhận identifier (tên method) đến một method và liên kết method này với loại dữ liệu cơ bản của đầu nhận. Trong ví dụ này, chúng ta khai báo một Vertex struct để chứa 2 trường floating point X và Y, và một method Abs. Trường nào bắt đầu bằng ký tự viết hoa là công khai (public), trường nào bắt đầu bằng ký tự viết thường là ẩn (private). Trường và method có thể định vị được thông qua ký hiệu * và & cho pointer giống như C. Chương trình trên in ra 5.

Interface

Loại interface là một tập method. Một giá trị của loại interface có thể chứa bất kỳ giá trị nào của method. Trong ví dụ trên, ta định nghĩa một interface Abser và một biến a của loại Abser. Chú ý là việc gán giá trị ở dòng 17 và 18 vẫn được nhưng gán ở dòng 22 không biên dịch được. Method Abs của Vertex mà chúng ta thấy ở hình trước đó có một trỏ pointer đến loại Vertex cho bộ nhận của nó, nên *Vertex tạo được Abser, nhưng Vertex lại không.

Switch

Khai báo switch trong Go tương tự như khai báo switch trong các ngôn ngữ C khác, trừ các khai báo case có thể là type hoặc một diễn đạt nào đó đến các giá trị đơn giản, và những case này tự động ngắt trừ khi chúng kết thúc bằng khai báo fallthrough. Những case này cũng sẽ được đánh giá theo trình tự khai báo.

Trình lặp Goroutine

Goroutine có thể xem là nét đặc trưng của Communicating Sequential Processes của Tony Hoare, với các dòng lệnh cực kỳ gọn nhẹ. Như dòng 16 trong ví dụ trên gọi ra hàm say không đồng thời với hàm say ở dòng 17. Goroutine, kênh channel và khai báo select định hình nên đặc điểm cốt lõi của ngôn ngữ lập trình có là năng mở rộng tính đồng loạt rất cao như Go, một trong những điểm mạnh của ngôn ngữ này. Go cũng có các đối tượng (object) đồng bộ truyền thống nhưng hiếm khi cần đến chúng. Chương trình trên sẽ xuất ra:

hello
world
hello
world
hello
world
hello
world
hello

Kênh channel

Kênh channel trong Go mang lại cơ chế thực thi các hàm đồng loạt để giao tiếp bằng cách gửi và nhận các giá trị của một type cụ thể. Giá trị này của một kênh channel chưa được khởi chạy là nil. Ở dòng 16, chúng ta tạo một kênh channel 2 chiều với giá trị số nguyên. Chúng ta cũng có thể tạo một kênh gửi đẳng hướng <-c và nhận đẳng hướng c<-. Ở dòng 17 và 18, chúng ta gọi sum bất đồng bộ với slice của nửa đầu và nửa thứ 2 của a. Ở dòng 19, các biến số nguyên x và y nhận 2 tổng từ channel này. Ở dòng 7, dấu gạch dưới _, bộ nhận diện identifier trống, nghĩa là bỏ qua giá trị kết quả đầu tiên của vòng lặp for..range, là số chỉ mục index. Chương trình sẽ xuất ra:

17 -5 12

Range và close

Người gửi có thể đóng (close) một kênh channel để cho chương trình biết rằng không còn giá trị nào được gửi nữa. Bộ nhận receiver có thể thử lại liệu một kênh channel đã được đóng hay chưa bằng cách gán một tham số thứ 2 vào khai báo đầu nhận. Một vòng lặp loop for i := range c nhận các giá trị liên tục từ channel cho đến khi channel đó đóng. Cap của channel là dung lượng, nghĩa là kích thước bộ đệm trong channel, là tham số tuỳ chọn thứ 2 mà bạn có thể thiết lập cho channel như ở dòng 17. Chú ý là hình thức gọn nhẹ trong khai báo giá trị gán ở hàm fibonacci. Chương trình sẽ xuất ra 10 giá trị đầu tiên trong chuỗi Fibonacci, từ 0-34.

Select

Một khai báo select chọn một tập send hoặc receive để chạy. Có vẻ nó giống với khai báo switch nhưng select lại hướng đến các thao tác về giao tiếp hơn. Một select chặn lại cho đến khi một trong những case của nó có thể chạy được, sau đó nó thực thi case đó. Nó chọn một case ngẫu nhiên nếu nhiều case đều chạy được. Ở đây là hàm main gọi hàm fibonacci với hai kênh channel không bộ đệm, một channel cho kết quả và một channel cho tín hiệu quit. Hàm fibonacci sử dụng khai báo select để chờ cả hai kênh. Hàm go đồng bộ và bất đồng bộ bắt đầu chạy ở dòng 21, chờ để nhận giá trị ở dòng 23 sau đó xuất kết quả. Sau 10 giá trị, nó chạy kênh quit, nên hàm fibonacci biết lúc nào thì dừng.

Các mẫu chạy đồng loạt, ví dụ 1

Trong ví dụ này, chúng ta dùng select để tạo một fanIn goroutine, kết hợp 2 kênh channel nhập chuỗi, input1 và input2, đổ vào một kênh channel xuất không bộ đệm, c. Khai báo select cho phép fanIn nghe 2 kênh channel nhập đồng thời và xử lý để chuẩn bị cho kênh channel xuất. Chương trình không bị lỗi khi cả hai case này dùng cùng tên biến tạm để lưu chuỗi từ kênh nhập. Ví dụ này có trong Concurrency Pattern của Rob Pike hồi năm 2012.

Các mẫu chạy đồng loạt, ví dụ 2

Ví dụ này thiết lập một tìm kiếm song song trên internet, cũng là kiểu tương tự như Google hiện nay. Bắt đầu, replicas …Search là một tham số động gắn với hàm này; cả Search và Result là các type được định nghĩa tuỳ chỗ. Bộ gọi caller chuyển các hàm máy chủ tìm kiếm N sang hàm First, trong hàm này tạo ra một kênh c chứa kết quả và định nghĩa một hàm yêu cầu máy chủ thứ i, và lưu nó làm trong searchReplica. Sau đó, First gọi searchReplica bất đồng bộ đối với mọi máy chủ N, luôn luôn trả kết quả về channel c, và trả về kết quả đầu tiên ngược lại từ các máy chủ N. Ví dụ này có trong Concurrency Pattern của Rob Pike hồi năm 2012.

Gói http

Gói net/http của Go cung cấp thiết lập HTTP phía client và máy chủ. Ví dụ này thiết lập một máy chủ web cơ bản, trả về nội dung của thư mục /usr/share/doc trên trình duyệt phía client. Ví dụ này không chạy được với môi trường trực tuyến Go Playground nhưng chỉ chạy trên dòng lệnh Mac, trả về một trình duyệt web với địa chỉ http://localhost:8080/:

bash/
ccid/
cups/
groff/
ntp/
postfix/

Gói template

Gói Go html/template thiết lập các mẫu template để tạo các mẫu xuất HTML an toàn, chống tấn công chèn code. Dùng các gói template này, ví dụ trên có thể tạo ra một chuỗi ký tự JavaScript có thể chạy được, Hello, <script>alert('you have been pwned')</script>!

0