Posts (Golang) Tóm tắt cú pháp
Post
Cancel

(Golang) Tóm tắt cú pháp

Các thành phần cơ bản

Code Golang có thể được viết với bộ mã Unicode UTF-8.

Comments

Gồm 2 loại:

  • Comment theo hàng: // hi there.
  • Comment chung: /* hi there */.

Số nguyên

Gồm 4 loại: thập phân, nhị phân (0b, 0B), octal (0o, 0O) và hexa (0x, 0X). Có thể dùng _ để ngăn cách giữa các chữ số, cho dễ đọc.

Số thực

Gồm 2 loại: số thực với chữ số thập phân (1.2e-2), số thực với chữ số hexa (0X1p-2)

Số ảo

Là phần ảo của số phức. Cấu tạo: 1i, 0xabci, .25i

Rune

Là một giá trị nguyên biểu thị 1 Unicode code point. Cấu tạo: 'a', '\n', 'á'

String

Gồm 2 loại: raw (ngăn cách bởi 2 dấu `) và interpreted (ngăn cách bởi 2 dấu “).

  • Raw string gồm các kí tự unicode và newline.
  • Interpreted string gồm các giá trị unicode và giá trị byte.

Declarations

ID trống

Được biểu thị bằng dấu _. Mục đích: đại diện cho anonymous placeholder, đỡ xài ID thật.

Các ID đã được khai báo sẵn

Các ID sau đã được khai báo trước ở universe block.

  • Kiểu:
    1
    2
    3
    
    bool byte complex64 complex128 error float32 float64
    int int8 int16 int32 int64 rune string
    uint uint8 uint16 uint32 uint64 uintptr
    
  • Hằng: true false iota
  • Giá trị zero: nil
  • Các hàm:
    1
    2
    
    append cap close complex copy delete imag len
    make new panic print println real recover
    

Các ID được export

Một ID có thể được export để cho phép truy cập vào ID đó từ package khác. Điều kiện:

  • Kí tự đầu tiên trong tên phải in hoa.
  • ID đó đã được khai báo trong block của pakage hoặc nó là field name, method name.

Khai báo hằng

Cú pháp:

1
2
3
4
5
6
7
8
const Pi float64 = 3.14159 // Đầy đủ
const zero = 0 // Không có kiểu
// Khai báo nhiều biến một lúc
const (
    size int64 = 1024
    eof = -1
)
const a, b = 1, 2

Có thể dùng iota để khai báo các giá trị tuần tự hiệu quả. iota đại diện cho index của khai báo hằng khi khai báo nhiều hằng trong (), bắt đầu từ 0.

1
2
3
4
5
6
const (
    a = 1 << iota   // a = 1
    b = 1 << iota   // b = 2
    c = 3           // c = 3
    d = 1 << iota   // d = 8
)

Khai báo kiểu

Ràng buộc một ID (type name) với một kiểu. Khai báo kiểu gồm 2 loại: khai báo alias và định nghĩa kiểu.

  • Cú pháp:
    1
    2
    3
    4
    5
    6
    7
    
    type nodeList = []*Node // Khai báo alias
    type Point struct{x, y float64} // Định nghĩa kiểu
    // Khai báo nhiều kiểu một lúc
    type (
      nodeList = []*Node
      Point struct{x, y float64}
    )
    
  • Khai báo alias: ràng buộc ID với một kiểu cho trước id = type.
  • Định nghĩa kiểu: tạo ra một kiểu mới, riêng biệt, khác biệt với kiểu cấu thành nó id type.

Khai báo biến

Cú pháp: var <tên biến> <kiểu> = <giá trị> Khai báo biến sẽ tạo một hoặc nhiều biến, ràng buộc ID vào, và cho nó kiểu và giá trị khởi tạo.

1
2
3
4
5
6
7
var i int
var x = 0
var x, y float64 = -1, -2
var (
    i       int
    u, v    = 2.0, 3.0
)
  • Nếu không có giá trị khởi tạo, thì mặc định sẽ khởi tạo zero value.
  • Nếu không khai báo kiểu, thì sẽ suy diễn kiểu từ giá trị khởi tạo.
  • Không thể dùng var i = nil.
  • Compiler sẽ báo lỗi nếu như khai báo biến trong thân hàm mà không dùng.

Khai báo biến ngắn gọn

Cú pháp: <tên biến> := <giá trị>. Giống như khai báo biến, không có từ khóa var và không cần khai báo kiểu, chỉ cần khai báo giá trị khởi tạo

1
2
i, j := 0, 10
_, y, _ := coord(p)
  • Có thể khai báo lại các biến đã được khai báo trước đó, với điều kiện là cùng kiểu.
  • Khai báo lại sẽ không tạo biến mới, mà là gán giá trị mới vào biến cũ.
  • Chỉ xuất hiện trong các hàm, thường dùng để khai báo các biến tạm trong các if, for, switch.

Khai báo hàm

Cú pháp: func <tên hàm> <signature> <thân hàm>?

1
2
3
4
5
6
7
func min(x int, y int) int {
	if x < y {
		return x
	}
	return y
}
func flushICache(begin, end uintptr)  // hiện thực ở ngoài
  • Signature định nghĩa parameters và result.
  • Thân hàm phải kết thúc bằng các terminating statements.
  • Thân hàm có thể không có, và hàm đó sẽ được hiện thực ở ngoài.

Khai báo phương thức (method)

Cú pháp: func <receiver> <tên phương thức> <signature> <thân hàm>?. Thuộc tính là một hàm có receiver. Khác ở hàm là có thêm ràng buộc với base type của receiver. Vì Go không có class nên đây là thay thế cho method của class trong OOP.

  • Base type của receiver không là con trỏ hay interface, và phải được định nghĩa trong cùng package với method.
  • Receiver là danh sách 1 tham số, có kiểu đã định nghĩa T (giá trị) hoặc con trỏ tới T (con trỏ, thường dùng hơn để thay đổi trực tiếp các thuộc tính).
  • Kiểu của method là kiểu có hàm, với receiver là argument đầu tiên.
    1
    2
    3
    4
    5
    6
    7
    8
    
    func (p *Point) Length() float64 {
      return math.Sqrt(p.x * p.x + p.y * p.y)
    }
    func (p *Point) Scale(factor float64) {
      p.x *= factor
      p.y *= factor
    }
    // 
    

Expression

Expression trả về kết quả tính toán khi áp dụng các phép toán, hàm lên các toán hạng (operands).

Qualified ID

Là ID đi kèm với package name ở trước. Package phải được import từ trước. Cú pháp: <package name>.<ID>

Composite literals

Là giá trị của struct, array, slice, map và tạo giá trị mới mỗi khi được tính.

Function literals

Đại diện cho anonymous function. Cú pháp: func <Signature> <Body>. Function literal có thể được gán vào biến, hoặc gọi trực tiếp.

1
2
f := func(x, y int) int { return x + y }
func(x, y int) int { return x + y } (1, 2)

Selector expression

Cú pháp: <ID>.<selector>. Để lấy giá trị của thuộc tính selector trong ID.

  • Nếu ID là kiểu pointer / interface, và có giá trị nil thì ID.f sẽ gây ra lỗi runtime.
  • Nếu x là con trỏ thì x.f == (*x).f.

Method expression

Cú pháp: <receiver>.<tên method>()

Index expression

Slice expression

Gồm 2 loại: đơn giản và đầy đủ.

  • Đơn giản: a[low:high]
  • Phức tạp: a[low:high:max], giống như đơn giản nhưng có capacity là max - low.

Type assertions

Gọi hàm

Truyền tham số bằng …

Giúp truyền nhiều tham số vào hàm, trong khi khai báo hàm chỉ có 1 tham số (phải là tham số cuối). Tương đương với một mảng. Để truyền một mảng vào tham số kiểu này, sử dụng … ở sau tên mảng truyền vào.

1
2
3
4
5
func Greeting(prefix string, people ...string)
Greeting("nobody") // prefix = nobody
Greeting("hello", "A", "B", "C") // prefix = hello, people = []string{"A", "B", "C"}
s := []string{"A", "B"}
Greeting("goodbye", s...)

Toán tử

Toán tử giúp gom các toán hạng lại với nhau.

  • Toán tử số học: + - * / % & | ^ &^ << >>
  • Toán tử so sánh: == != < <= > >=
  • Toán tử luận lý: && || !
  • Toán tử địa chỉ: &a trả về con trỏ tới a, *p trả về giá trị được lưu tại địa chỉ trỏ bởi p.
  • Toán tử nhận (receive operator): <-ch trả về giá trị nhận (receive value) từ kênh ch. ch phải có kiểu kênh (channel).

Ép kiểu

Cú pháp: <kiểu> ( <expression> ). Ví dụ: int(a).

Statement

Statement giúp thay đổi trạng thái của chương trình.

Labeled

Cú pháp: ID: <Statement>. Labeled statement là mục tiêu của goto, breakcontinue.

Send

Cú pháp: <Channel> <- <Expression>. Mục đích: gửi giá trị vào một channel.

IncDec

Cú pháp: <Expression> (++ / --). Mục đích: tăng/giảm giá trị đi 1.

Gán

Cú pháp: <Expression_list> (= / <op>=) <Expression_list>. Cú pháp x <op>= y đồng nghĩa với x = x <op> y.

If

Cú pháp: If <Simple Stmt ;>? <Expression> <Block> else if ... else <Block>. Trước expression của If có thể có một statement đơn giản để khởi tạo trước.

Switch

Thay vì if chỉ cho phép rẽ 2 nhánh (true / false), switch cho phép rẽ nhiều nhánh. Có 2 loại: switch theo expression và switch theo kiểu.

Cú pháp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Theo expression
switch x := f(); tag {
    default: s3()
    case 0, 1, 2, 3: s1()
    case 4, 5, 6, 7: s2()
}
// Theo kiểu
switch i := x.(type) {
case nil:
	printString("x is nil")
case int:
	printInt(i)
case float64:
	printFloat64(i)  
case func(int) float64:
	printFunction(i)
case bool, string:
	printString("type is bool or string") 
default:
	printString("don't know the type")
}

For

Gồm 3 loại: điều kiện đơn, mệnh đề “for” và mệnh đề “range”.

  • Điều kiện đơn: giống như while trong C. Cú pháp: for a < b {}
  • Mệnh đề for: giống như for trong C. Cú pháp: for i:= 1; i < 2; i++ {}
  • Mệnh đề range: giống như foreach trong PHP. Cú pháp: for first, second := range range_exp {}. Có 4 loại range expression, gồm:
    • Array/slice: firsti (int), seconda[i].
    • String: firsti (int), second là kí tự tại i (rune).
    • Map (map[K](V)): first là key, second là value.
    • Channel: first là element, không có second.

Go

Lệnh go bắt đầu quá trình thực thi của một lệnh gọi hàm như một thread đồng thời, độc lập, hay còn gọi là goroutine, trong cùng không gian địa chỉ. Cú pháp: go Server().

Select

Lệnh select lựa chọn những phép send hoặc receive sẽ thực thi (dùng trong channel). Có cấu trúc khá giống như switch, nhưng các case liên quan đến các phép communication.

Cú pháp:

1
2
3
4
5
6
7
8
select {
    case i1 = <-c1:
        print("received")
    case c2 <- i2:
        print("send")
    default:
        print("no communication")
}

Return

Dùng để kết thúc hàm, và trả về giá trị. Cú pháp như thông thường. Cách return trống: return . Khi vào một hàm thì giá trị trả về luôn được khởi tạo là zero value.

Break

Dùng để thoát khỏi for, switch, select gần nhất. Cú pháp: break hoặc break Label. Nếu có Label thì Label đó phải chứa lệnh for chứa lệnh break, thường dùng để thoát khỏi nhiều vòng lặp.

Continue

Dùng để nhảy đến iteration tiếp theo trong for gần nhất. Cú pháp tương tự break (có Label).

Goto

Fallthrough

Cú pháp: fallthrough. Dùng để chuyển đến lệnh đầu tiên của case tiếp theo trong switch.

Defer

Cú pháp: defer <lệnh gọi hàm/phương thức>. Dùng để hoãn lệnh gọi hàm/phương thức cho đến khi return hàm ngoài thì sẽ chạy.

This post is licensed under CC BY 4.0 by the author.
Recent Update
Trending Tags
Contents

-

-

Trending Tags