Hướng dẫn Golang: Học ngôn ngữ lập trình Go cho người mới bắt đầu

Đi là gì?

Go (còn gọi là Golang) là ngôn ngữ lập trình mã nguồn mở được phát triển bởi Google. Nó là một ngôn ngữ biên dịch kiểu tĩnh. Go hỗ trợ lập trình đồng thời, tức là nó cho phép chạy nhiều tiến trình cùng một lúc. Điều này đạt được bằng cách sử dụng các kênh, goroutine, v.v. Ngôn ngữ Go có bộ sưu tập rác, chính nó thực hiện việc quản lý bộ nhớ và cho phép thực thi các chức năng bị trì hoãn.

Chúng ta sẽ tìm hiểu tất cả những điều cơ bản về Golang trong Hướng dẫn học ngôn ngữ Go này.

Cách tải xuống và cài đặt GO

Bước 1) Đến phần https://golang.org/dl/. Tải xuống tệp nhị phân cho hệ điều hành của bạn.

Bước 2) Double nhấp vào trình cài đặt và nhấp vào Chạy.

Bước 3) Nhấp vào Tiếp theo

Bước 4) Chọn thư mục cài đặt và nhấn Next.

Bước 5) Nhấp vào Kết thúc sau khi cài đặt hoàn tất.

Bước 6) Sau khi quá trình cài đặt hoàn tất, bạn có thể xác minh nó bằng cách mở terminal và gõ

go version

Điều này sẽ hiển thị phiên bản được cài đặt

Chương trình Go đầu tiên của bạn – Go Hello World!

Tạo một thư mục tên là StudyGo. Trong hướng dẫn ngôn ngữ Go này, chúng ta sẽ tạo các chương trình cờ vây bên trong thư mục này. Các tập tin Go được tạo bằng phần mở rộng .đi. Bạn có thể chạy các chương trình Go bằng cú pháp

go run <filename>

Tạo một tệp có tên first.go và thêm mã bên dưới vào đó và lưu

package main
import ("fmt")

func main() {
	fmt.Println("Hello World! This is my first Go program\n")
}

Điều hướng đến thư mục này trong thiết bị đầu cuối của bạn. Chạy chương trình bằng lệnh

hãy chạy trước đi.go

Bạn có thể thấy bản in đầu ra

Hello World! This is my first Go program

Bây giờ hãy thảo luận về chương trình trên.

gói chính – Mọi chương trình Ngôn ngữ Go phải bắt đầu bằng tên gói. Go cho phép chúng ta sử dụng các gói trong các chương trình go khác và do đó hỗ trợ khả năng sử dụng lại mã. Việc thực thi chương trình Go bắt đầu bằng mã bên trong gói có tên main.

import fmt – nhập gói fmt. Gói này thực hiện các chức năng I/O.

func main() – Đây là hàm bắt đầu thực hiện chương trình. Chức năng chính phải luôn được đặt trong gói chính. Trong hàm main(), bạn có thể viết mã bên trong { }.

fmt.Println – Thao tác này sẽ in văn bản trên màn hình bằng chức năng Println của fmt.

Lưu ý: Trong các phần bên dưới của hướng dẫn Go này, khi Bạn đề cập đến việc thực thi/chạy mã, điều đó có nghĩa là lưu mã vào một tệp có phần mở rộng .go và chạy mã đó bằng cú pháp

    go run <filename>

Loại dữ liệu

Các loại (kiểu dữ liệu) biểu thị loại giá trị được lưu trữ trong một biến, loại giá trị mà hàm trả về, v.v.

Có ba loại cơ bản trong Ngôn ngữ Go

Loại số – Biểu thị các giá trị số bao gồm số nguyên, dấu phẩy động và giá trị phức. Các loại số khác nhau là:

int8 – số nguyên có dấu 8 bit.

int16 – số nguyên có dấu 16 bit.

int32 – số nguyên có dấu 32 bit.

int64 – số nguyên có dấu 64 bit.

uint8 – số nguyên không dấu 8 bit.

uint16 – số nguyên không dấu 16 bit.

uint32 – số nguyên không dấu 32 bit.

uint64 – số nguyên không dấu 64 bit.

float32 – số dấu phẩy động 32 bit.

float64 – số dấu phẩy động 64 bit.

complex64 – có float32 phần thực và phần ảo.

complex128 – có float32 phần thực và phần ảo.

Các loại chuỗi – Biểu thị một chuỗi byte (ký tự). Bạn có thể thực hiện nhiều thao tác khác nhau trên chuỗi như nối chuỗi, trích xuất chuỗi con, v.v.

Các kiểu Boolean – Đại diện cho 2 giá trị đúng hoặc sai.

Giao diện Golang

Giao diện Golang là tập hợp các chữ ký phương thức được Loại sử dụng để thực hiện hành vi của các đối tượng. Mục tiêu chính của giao diện Golang là cung cấp chữ ký phương thức với tên, đối số và kiểu trả về. Việc khai báo và triển khai phương thức này tùy thuộc vào Loại. Một giao diện trong Golang có thể được khai báo bằng từ khóa “giao diện”.

Biến

Các biến trỏ đến một vị trí bộ nhớ lưu trữ một số loại giá trị. Tham số loại (theo cú pháp bên dưới) biểu thị loại giá trị có thể được lưu trữ ở vị trí bộ nhớ.

Biến có thể được khai báo bằng cú pháp

    var <variable_name> <type>

Khi bạn khai báo một biến thuộc loại Bạn có thể gán biến cho bất kỳ giá trị nào thuộc loại đó.

Bạn cũng có thể cung cấp giá trị ban đầu cho một biến trong quá trình khai báo bằng cách sử dụng

    var <variable_name> <type> = <value>

Nếu bạn khai báo biến có giá trị ban đầu, hãy suy ra loại biến từ loại giá trị được gán. Vì vậy, bạn có thể bỏ qua loại trong khi khai báo bằng cú pháp

    var <variable_name> = <value>

Ngoài ra, bạn có thể khai báo nhiều biến theo cú pháp

    var <variable_name1>, <variable_name2>  = <value1>, <value2>

Chương trình bên dưới trong hướng dẫn Go này có một số ví dụ về Golang về khai báo biến

 
package main
import "fmt"

func main() {
    //declaring a integer variable x
    var x int
    x=3 //assigning x the value 3 
    fmt.Println("x:", x) //prints 3
    
    //declaring a integer variable y with value 20 in a single statement and prints it
    var y int=20
    fmt.Println("y:", y)
    
    //declaring a variable z with value 50 and prints it
    //Here type int is not explicitly mentioned 
    var z=50
    fmt.Println("z:", z)
    
    //Multiple variables are assigned in single line- i with an integer and j with a string
    var i, j = 100,"hello"
    fmt.Println("i and j:", i,j)
}

Đầu ra sẽ là

x: 3
y: 20
z: 50
i and j: 100 hello

Go Language cũng cung cấp một cách dễ dàng để khai báo các biến có giá trị bằng cách bỏ qua từ khóa var bằng cách sử dụng

    <variable_name> := <value>

Lưu ý rằng bạn đã sử dụng := thay vì =. Bạn không thể sử dụng := chỉ để gán giá trị cho một biến đã được khai báo. := dùng để khai báo và gán giá trị.

Tạo một tệp có tên transfer.go với đoạn mã sau

package main
import ("fmt")

func main() {
	a := 20
	fmt.Println(a)

	//gives error since a is already declared
	a := 30
	fmt.Println(a)
}

Thực thi go run transfer.go để xem kết quả như sau

./assign.go:7:4: no new variables on left side of :=		

Các biến được khai báo không có giá trị ban đầu sẽ có 0 đối với kiểu số, sai đối với kiểu Boolean và chuỗi trống đối với chuỗi

Hằng số

Biến không đổi là những biến có giá trị không thể thay đổi sau khi được gán. Một hằng số trong ngôn ngữ lập trình Go được khai báo bằng từ khóa “const”

Tạo một tệp có tên là constant.go và với đoạn mã sau

package main
import ("fmt")

func main() {
	const b =10
	fmt.Println(b)
	b = 30
	fmt.Println(b)
}

Thực hiện go run constant.go để xem kết quả như sau

.constant.go:7:4: cannot assign to b

Ví dụ về vòng lặp

Vòng lặp được sử dụng để thực thi một khối câu lệnh lặp đi lặp lại dựa trên một điều kiện. Hầu hết các ngôn ngữ lập trình đều cung cấp 3 loại vòng lặp – for, while, do while. Nhưng ngôn ngữ lập trình Go chỉ hỗ trợ vòng lặp for.

Cú pháp của vòng lặp Golang for là

for initialisation_expression; evaluation_expression; iteration_expression{
   // one or more statement
}

Biểu thức khởi tạo được thực thi đầu tiên (và chỉ một lần) trong vòng lặp for Golang.

Sau đó, biểu thức đánh giá được đánh giá và nếu đúng thì mã bên trong khối sẽ được thực thi.

Id biểu thức lặp được thực thi và biểu thức đánh giá được đánh giá lại. Nếu đúng thì khối câu lệnh sẽ được thực thi lại. Điều này sẽ tiếp tục cho đến khi biểu thức đánh giá trở thành sai.

Sao chép chương trình bên dưới vào một tệp và thực hiện nó để xem Golang cho vòng lặp in các số từ 1 đến 5

package main
import "fmt"

func main() {  
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
    }
}

Đầu ra là

1
2
3
4
5

Nếu khác

Nếu khác là một tuyên bố có điều kiện. Synax là

if condition{
// statements_1
}else{
// statements_2
}

Ở đây điều kiện được đánh giá và nếu câu lệnh_1 đúng sẽ được thực thi thì câu lệnh_2 khác sẽ được thực thi.

Bạn cũng có thể sử dụng câu lệnh if mà không cần else. Bạn cũng có thể có các câu lệnh if else theo chuỗi. Các chương trình dưới đây sẽ giải thích thêm về if else.

Thực hiện chương trình dưới đây. Nó kiểm tra xem một số x có nhỏ hơn 10 hay không. Nếu vậy, nó sẽ in ra “x nhỏ hơn 10”

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x < 10
        fmt.Println("x is less than 10")
    } 
}

Ở đây vì giá trị của x lớn hơn 10 nên câu lệnh bên trong điều kiện khối if sẽ không được thực thi.

Bây giờ hãy xem chương trình dưới đây. Trong hướng dẫn ngôn ngữ lập trình Go này, chúng ta có một khối else sẽ được thực thi khi đánh giá if không thành công.

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else {
        //Executes if x >= 10
        fmt.Println("x is greater than or equals 10")
    }
}

Chương trình này sẽ cung cấp cho bạn đầu ra

x is greater than or equals 10

Bây giờ trong hướng dẫn Go này, chúng ta sẽ thấy một chương trình có nhiều khối if else (xâu chuỗi nếu khác). Thực hiện ví dụ Go bên dưới. Nó kiểm tra xem một số có nhỏ hơn 10 hay nằm trong khoảng 10-90 hay lớn hơn 90 hay không.

package main
import "fmt"

func main() {  
    var x = 100
    if x < 10 {
        //Executes if x is less than 10
        fmt.Println("x is less than 10")
    } else if x >= 10 && x <= 90 {
        //Executes if x >= 10 and x<=90
        fmt.Println("x is between 10 and 90")
    } else {
        //Executes if both above cases fail i.e x>90
        fmt.Println("x is greater than 90")
    }
}

Đầu tiên, điều kiện if sẽ kiểm tra xem x có nhỏ hơn 10 hay không. Vì vậy, nó sẽ kiểm tra điều kiện tiếp theo (nếu không) liệu nó có nằm trong khoảng từ 10 đến 90 hay không, điều này cũng sai. Vì vậy, sau đó nó thực thi khối bên dưới phần khác để đưa ra đầu ra

x is greater than 90

Công tắc điện

Switch là một câu lệnh có điều kiện khác. Câu lệnh chuyển đổi đánh giá một biểu thức và kết quả được so sánh với một tập hợp các giá trị (trường hợp) có sẵn. Khi tìm thấy kết quả khớp, các câu lệnh liên quan đến (trường hợp) khớp đó sẽ được thực thi. Nếu không tìm thấy kết quả phù hợp thì sẽ không có gì được thực thi. Bạn cũng có thể thêm trường hợp mặc định để chuyển đổi, trường hợp này sẽ được thực thi nếu không tìm thấy kết quả khớp nào khác. Cú pháp của switch là

switch expression {
    case value_1:
        statements_1
    case value_2:
        statements_2
    case value_n:
        statements_n
    default:
        statements_default
    }

Ở đây giá trị của biểu thức được so sánh với các giá trị trong từng trường hợp. Khi tìm thấy kết quả khớp, các câu lệnh liên quan đến trường hợp đó sẽ được thực thi. Nếu không tìm thấy kết quả khớp thì các câu lệnh trong phần mặc định sẽ được thực thi.

Thực hiện chương trình dưới đây

package main
import "fmt"

func main() {  
    a,b := 2,1
    switch a+b {
    case 1:
        fmt.Println("Sum is 1")
    case 2:
        fmt.Println("Sum is 2")
    case 3:
        fmt.Println("Sum is 3")
    default:
        fmt.Println("Printing default")
    }
}

Bạn sẽ nhận được đầu ra như

Sum is 3		

Thay đổi giá trị của a và b thành 3 và kết quả sẽ là

Printing default

Bạn cũng có thể có nhiều giá trị trong một trường hợp bằng cách phân tách chúng bằng dấu phẩy.

Mảng

Mảng biểu thị một kích thước cố định, được đặt tên theo thứ tự các phần tử cùng loại. Bạn không thể có một mảng chứa cả số nguyên và ký tự trong đó. Bạn không thể thay đổi kích thước của mảng khi bạn xác định kích thước.

Cú pháp khai báo một mảng là

var arrayname [size] type

Mỗi phần tử mảng có thể được gán giá trị bằng cú pháp

arrayname [index] = value

Chỉ số mảng bắt đầu từ 0 đến cỡ-1.

Bạn có thể gán giá trị cho các phần tử mảng trong khi khai báo bằng cú pháp

arrayname := [size] type {value_0,value_1,…,value_size-1} 

Bạn cũng có thể bỏ qua tham số kích thước trong khi khai báo mảng bằng các giá trị bằng cách thay thế kích thước bằng ... và trình biên dịch sẽ tìm độ dài từ số lượng giá trị. Cú pháp là

arrayname :=  […] type {value_0,value_1,…,value_size-1}

Bạn có thể tìm độ dài của mảng bằng cách sử dụng cú pháp

len(arrayname)

Thực hiện ví dụ Go bên dưới để hiểu mảng

package main
import "fmt"

func main() {  
    var numbers [3] string //Declaring a string array of size 3 and adding elements 
    numbers[0] = "One"
    numbers[1] = "Two"
    numbers[2] = "Three"
    fmt.Println(numbers[1]) //prints Two
    fmt.Println(len(numbers)) //prints 3
    fmt.Println(numbers) // prints [One Two Three]

    directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements 
    fmt.Println(directions) //prints [1 2 3 4 5]
    fmt.Println(len(directions)) //prints 5

    //Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array)
    //fmt.Println(directions[5]) 
}

Đầu ra

Two
3
[One Two Three]
[1 2 3 4 5]
5

Chức năng cắt và nối Golang

Slice là một phần hoặc một đoạn của mảng. Hoặc đó là chế độ xem hoặc chế độ xem một phần của mảng cơ bản mà nó trỏ tới. Bạn có thể truy cập các phần tử của một lát bằng cách sử dụng tên lát và số chỉ mục giống như bạn thực hiện trong một mảng. Bạn không thể thay đổi độ dài của mảng nhưng bạn có thể thay đổi kích thước của một lát cắt.

Nội dung của một lát cắt thực chất là các con trỏ tới các phần tử của một mảng. Nó có nghĩa là nếu bạn thay đổi bất kỳ phần tử nào trong một lát cắt thì nội dung mảng cơ bản cũng sẽ bị ảnh hưởng.

Cú pháp để tạo một slice là

var slice_name [] type = array_name[start:end]

Điều này sẽ tạo một lát cắt có tên slice_name từ một mảng có tên array_name với các phần tử ở chỉ mục bắt đầu đến kết thúc-1.

Bây giờ trong hướng dẫn Golang này, chúng ta sẽ thực hiện chương trình bên dưới. Chương trình sẽ tạo một slice từ mảng và in nó. Ngoài ra, bạn có thể thấy rằng việc sửa đổi nội dung trong lát cắt sẽ sửa đổi mảng thực tế.

package main
import "fmt"

func main() {  
    // declaring array
    a := [5] string {"one", "two", "three", "four", "five"}
    fmt.Println("Array after creation:",a)

    var b [] string = a[1:4] //created a slice named b
    fmt.Println("Slice after creation:",b)

    b[0]="changed" // changed the slice data
    fmt.Println("Slice after modifying:",b)
    fmt.Println("Array after slice modification:",a)
}

Điều này sẽ in kết quả như

Array after creation: [one two three four five]
Slice after creation: [two three four]
Slice after modifying: [changed three four]
Array after slice modification: [one changed three four five]

Có một số chức năng nhất định như Golang len, bổ sung Golang mà bạn có thể áp dụng trên các lát

len(slice_name) – trả về chiều dài của lát cắt

nối thêm (lát_tên, giá trị_1, giá trị_2) – Phần bổ sung Golang được sử dụng để nối giá trị_1 và giá trị_2 vào một slice hiện có.

nối thêm(slice_nale1,slice_name2…) – nối slice_name2 vào slice_name1

Thực hiện chương trình sau.

package main
import "fmt"

func main() {  
	a := [5] string {"1","2","3","4","5"}
	slice_a := a[1:3]
	b := [5] string {"one","two","three","four","five"}
	slice_b := b[1:3]

    fmt.Println("Slice_a:", slice_a)
    fmt.Println("Slice_b:", slice_b)
    fmt.Println("Length of slice_a:", len(slice_a))
    fmt.Println("Length of slice_b:", len(slice_b))

    slice_a = append(slice_a,slice_b...) // appending slice
    fmt.Println("New Slice_a after appending slice_b :", slice_a)
    
    slice_a = append(slice_a,"text1") // appending value
    fmt.Println("New Slice_a after appending text1 :", slice_a)
}

Đầu ra sẽ là

Slice_a: [2 3]
Slice_b: [two three]
Length of slice_a: 2
Length of slice_b: 2
New Slice_a after appending slice_b : [2 3 two three]
New Slice_a after appending text1 : [2 3 two three text1]

Đầu tiên chương trình tạo 2 lát cắt và in ra chiều dài của nó. Sau đó, nó nối thêm lát cắt này với lát cắt khác và sau đó nối thêm một chuỗi vào lát cắt kết quả.

Chức năng

Hàm đại diện cho một khối câu lệnh thực hiện một nhiệm vụ cụ thể. Khai báo hàm cho chúng ta biết tên hàm, kiểu trả về và tham số đầu vào. Định nghĩa hàm đại diện cho mã chứa trong hàm. Cú pháp khai báo hàm là

func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}

Các tham số và kiểu trả về là tùy chọn. Ngoài ra, bạn có thể trả về nhiều giá trị từ một hàm.

Bây giờ trong hướng dẫn Golang này, hãy chạy ví dụ Golang sau. Ở đây hàm có tên calc sẽ chấp nhận 2 số và thực hiện phép cộng, phép trừ và trả về cả hai giá trị.

package main
import "fmt"

//calc is the function name which accepts two integers num1 and num2
//(int, int) says that the function returns two values, both of integer type.
func calc(num1 int, num2 int)(int, int) {  
    sum := num1 + num2
    diff := num1 - num2
    return sum, diff
}

func main() {  
    x,y := 15,10

    //calls the function calc with x and y an d gets sum, diff as output
    sum, diff := calc(x,y) 
    fmt.Println("Sum",sum)
    fmt.Println("Diff",diff) 
}

Đầu ra sẽ là

Sum 25
Diff 5

Gói

Các gói được sử dụng để tổ chức mã. Trong một dự án lớn, việc viết mã trong một tệp duy nhất là không khả thi. Ngôn ngữ lập trình Go cho phép chúng ta tổ chức mã theo các gói khác nhau. Điều này làm tăng khả năng đọc mã và khả năng sử dụng lại. Một chương trình Go có thể thực thi phải chứa một gói có tên main và việc thực thi chương trình bắt đầu từ hàm có tên main. Bạn có thể nhập các gói khác vào chương trình của chúng tôi bằng cú pháp

import package_name

Chúng ta sẽ xem và thảo luận trong hướng dẫn Golang này, cách tạo và sử dụng các gói trong ví dụ Golang sau.

Bước 1) Tạo một tệp có tên pack_example.go và thêm mã bên dưới

package main
import "fmt"
//the package to be created
import "calculation"

func main() {  
	x,y := 15,10
	//the package will have function Do_add()
sum := calculation.Do_add(x,y)
fmt.Println("Sum",sum) 
}

Trong chương trình trên, fmt là gói mà ngôn ngữ lập trình Go cung cấp cho chúng ta chủ yếu cho mục đích I/O. Ngoài ra, bạn có thể thấy một gói có tên là tính toán. Bên trong hàm main() bạn có thể thấy tổng bước := tính toán.Do_add(x,y). Điều đó có nghĩa là bạn đang gọi hàm Do_add từ tính toán gói.

Bước 2) Trước tiên, bạn nên tạo phép tính gói bên trong một thư mục có cùng tên trong thư mục src của go. Đường dẫn đã cài đặt có thể được tìm thấy từ biến PATH.

Đối với mac, tìm đường dẫn bằng cách thực thi echo $PATH

Vậy đường dẫn là /usr/local/go

Đối với windows, tìm đường dẫn bằng cách thực thi echo %GOROOT%

Ở đây đường dẫn là C:\Go\

Bước 3) Điều hướng đến thư mục src (/usr/local/go/src cho mac và C:\Go\src cho windows). Bây giờ từ mã, tên gói là tính toán. Go yêu cầu gói phải được đặt trong một thư mục cùng tên trong thư mục src. Tạo một thư mục có tên tính toán trong thư mục src.

Bước 4) Tạo một tệp có tên calc.go (Bạn có thể đặt bất kỳ tên nào, nhưng tên gói trong mã rất quan trọng. Ở đây nó phải là phép tính) bên trong thư mục tính toán và thêm mã bên dưới

package calculation
  
func Do_add(num1 int, num2 int)(int) {
    sum := num1 + num2
    return sum
}

Bước 5) Chạy lệnh go install từ thư mục tính toán để biên dịch calc.go.

Bước 6) Bây giờ hãy quay lại package_example.go và chạy go run package_example.go. Đầu ra sẽ là Sum 25.

Lưu ý rằng tên của hàm Do_add bắt đầu bằng chữ in hoa. Điều này là do trong Go nếu tên hàm bắt đầu bằng chữ in hoa, điều đó có nghĩa là các chương trình khác có thể nhìn thấy (truy cập) nó, các chương trình khác không thể truy cập nó. Nếu tên hàm là do_add thì bạn đã gặp lỗi

không thể tham khảo tên chưa được xuất.calc..

Trì hoãn và xếp chồng trì hoãn

Câu lệnh trì hoãn được sử dụng để trì hoãn việc thực thi lệnh gọi hàm cho đến khi hàm chứa câu lệnh trì hoãn hoàn thành việc thực thi.

Hãy tìm hiểu điều này với một ví dụ:

package main
import "fmt"

func sample() {  
    fmt.Println("Inside the sample()")
}
func main() {  
    //sample() will be invoked only after executing the statements of main()
    defer sample()
    fmt.Println("Inside the main()")
}

Đầu ra sẽ là

Inside the main()
Inside the sample()

Ở đây, việc thực thi sample() được hoãn lại cho đến khi quá trình thực thi hàm kèm theo (main()) hoàn tất.

Xếp chồng trì hoãn đang sử dụng nhiều câu lệnh trì hoãn. Giả sử bạn có nhiều câu lệnh trì hoãn bên trong một hàm. Go đặt tất cả các lệnh gọi hàm bị trì hoãn vào một ngăn xếp và khi hàm kèm theo trả về, các hàm được xếp chồng sẽ được thực thi trong Thứ tự vào trước ra trước (LIFO). Bạn có thể thấy điều này trong ví dụ dưới đây.

Thực thi đoạn mã dưới đây

package main
import "fmt"

func display(a int) {  
    fmt.Println(a)
}
func main() {  
    defer display(1)
    defer display(2)
    defer display(3)
    fmt.Println(4)
}

Đầu ra sẽ là

4
3
2
1			

Ở đây, mã bên trong main() thực thi trước, sau đó các lệnh gọi hàm trì hoãn được thực thi theo thứ tự ngược lại, tức là 4, 3,2,1.

con trỏ

Trước khi giải thích về con trỏ, trước tiên chúng ta hãy thảo luận về toán tử '&'. Toán tử '&' được sử dụng để lấy địa chỉ của một biến. Nó có nghĩa là '&a' sẽ in địa chỉ bộ nhớ của biến a.

Trong hướng dẫn Golang này, chúng tôi sẽ thực thi chương trình bên dưới để hiển thị giá trị của một biến và địa chỉ của biến đó

package main
import "fmt"

func main() {
	a := 20
	fmt.Println("Address:",&a)
	fmt.Println("Value:",a)
}

Kết quả sẽ là

Address: 0xc000078008
Value: 20

Một biến con trỏ lưu trữ địa chỉ bộ nhớ của một biến khác. Bạn có thể định nghĩa một con trỏ bằng cú pháp

	var variable_name *type

Dấu hoa thị(*) biểu thị biến là con trỏ. Bạn sẽ hiểu rõ hơn bằng cách thực hiện chương trình dưới đây

package main
import "fmt"

func main() {
	//Create an integer variable a with value 20
	a := 20
	
	//Create a pointer variable b and assigned the address of a
	var b *int = &a

	//print address of a(&a) and value of a  
	fmt.Println("Address of a:",&a)
	fmt.Println("Value of a:",a)

	//print b which contains the memory address of a i.e. &a
	fmt.Println("Address of pointer b:",b)

	//*b prints the value in memory address which b contains i.e. the value of a
	fmt.Println("Value of pointer b",*b)

	//increment the value of variable a using the variable b
	*b = *b+1

	//prints the new value using a and *b
	fmt.Println("Value of pointer b",*b)
	fmt.Println("Value of a:",a)}

Đầu ra sẽ là

Address of a: 0x416020
Value of a: 20
Address of pointer b: 0x416020
Value of pointer b 20
Value of pointer b 21
Value of a: 21

Cấu trúc

Cấu trúc là kiểu dữ liệu do người dùng xác định, bản thân nó chứa thêm một phần tử cùng loại hoặc khác loại.

Sử dụng cấu trúc là một quá trình gồm 2 bước.

Đầu tiên, tạo (khai báo) một kiểu cấu trúc

Thứ hai, tạo các biến thuộc loại đó để lưu trữ giá trị.

Cấu trúc chủ yếu được sử dụng khi bạn muốn lưu trữ dữ liệu liên quan với nhau.

Hãy xem xét một phần thông tin nhân viên có tên, tuổi và địa chỉ. Bạn có thể xử lý việc này theo 2 cách

Tạo 3 mảng – một mảng lưu trữ tên của nhân viên, một mảng lưu tuổi và mảng thứ ba lưu trữ tuổi.

Khai báo một kiểu cấu trúc với 3 trường- tên, địa chỉ và tuổi. Tạo một mảng kiểu cấu trúc đó trong đó mỗi phần tử là một đối tượng cấu trúc có tên, địa chỉ và tuổi.

Cách tiếp cận đầu tiên không hiệu quả. Trong các loại kịch bản này, các cấu trúc sẽ thuận tiện hơn.

Cú pháp khai báo một cấu trúc là

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Một ví dụ về khai báo cấu trúc là

type emp struct {
    name string
    address string
    age int
}

Ở đây một kiểu do người dùng định nghĩa mới có tên emp được tạo. Bây giờ, bạn có thể tạo các biến kiểu emp bằng cú pháp

	var variable_name struct_name

Một ví dụ là

var empdata1 emp 

Bạn có thể đặt giá trị cho empdata1 là

empdata1.name = "John"
	empdata1.address = "Street-1, Bangalore"
	empdata1.age = 30

Bạn cũng có thể tạo một biến cấu trúc và gán giá trị bằng

empdata2 := emp{"Raj", "Building-1, Delhi", 25}

Ở đây, bạn cần duy trì thứ tự của các phần tử. Raj sẽ được ánh xạ tới tên, phần tử tiếp theo là địa chỉ và phần tử cuối cùng là tuổi.

Thực thi mã dưới đây

package main
import "fmt"

//declared the structure named emp
type emp struct {
        name string
        address string
        age int
}       

//function which accepts variable of emp type and prints name property
func display(e emp) {
          fmt.Println(e.name)
}

func main() {
// declares a variable, empdata1, of the type emp
var empdata1 emp
//assign values to members of empdata1
empdata1.name = "John"
empdata1.address = "Street-1, London"
empdata1.age = 30

//declares and assign values to variable empdata2 of type emp
empdata2 := emp{"Raj", "Building-1, Paris", 25}

//prints the member name of empdata1 and empdata2 using display function
display(empdata1)
display(empdata2)
}

Đầu ra

John
Raj

Phương thức (không phải hàm)

Một phương thức là một hàm có đối số người nhận. Archivề mặt kiến ​​trúc, nó nằm giữa từ khóa func và tên phương thức. Cú pháp của một phương thức là

func (variable variabletype) methodName(parameter1 paramether1type) {  
}

Hãy chuyển đổi chương trình ví dụ trên để sử dụng các phương thức thay vì hàm.

package main
import "fmt"

//declared the structure named emp
type emp struct {
    name string
    address string
    age int
}

//Declaring a function with receiver of the type emp
func(e emp) display() {
    fmt.Println(e.name)
}

func main() {
    //declaring a variable of type emp
    var empdata1 emp
    
    //Assign values to members
    empdata1.name = "John"
    empdata1.address = "Street-1, Lodon"
    empdata1.age = 30

    //declaring a variable of type emp and assign values to members
    empdata2 := emp {
        "Raj", "Building-1, Paris", 25}

    //Invoking the method using the receiver of the type emp
   // syntax is variable.methodname()
    empdata1.display()
    empdata2.display()
}

Go không phải là ngôn ngữ hướng đối tượng và nó không có khái niệm về lớp. Các phương thức mang lại cảm giác về những gì bạn làm trong các chương trình hướng đối tượng trong đó các hàm của một lớp được gọi bằng cú pháp objectname.functionname()

Truy cập đồng thời

Go hỗ trợ thực hiện đồng thời các nhiệm vụ. Điều đó có nghĩa là Go có thể thực thi nhiều tác vụ cùng một lúc. Nó khác với khái niệm song song. Trong cơ chế song song, một tác vụ được chia thành các tác vụ con nhỏ và được thực thi song song. Nhưng đồng thời, nhiều tác vụ đang được thực thi đồng thời. Tính đồng thời đạt được trong Go bằng cách sử dụng Goroutine và Kênh.

Goroutine

Goroutine là một hàm có thể chạy đồng thời với các hàm khác. Thông thường, khi một hàm được gọi, điều khiển sẽ được chuyển sang hàm được gọi và sau khi điều khiển thực thi hoàn thành sẽ quay trở lại hàm gọi. Chức năng gọi sau đó tiếp tục thực hiện. Hàm gọi chờ hàm được gọi hoàn thành việc thực thi trước khi tiếp tục với phần còn lại của câu lệnh.

Nhưng trong trường hợp goroutine, hàm gọi sẽ không đợi việc thực thi hàm được gọi hoàn tất. Nó sẽ tiếp tục thực thi với các câu lệnh tiếp theo. Bạn có thể có nhiều goroutines trong một chương trình.

Ngoài ra, chương trình chính sẽ thoát sau khi hoàn thành việc thực thi các câu lệnh của mình và sẽ không chờ hoàn thành các goroutine được gọi.

Goroutine được gọi bằng cách sử dụng từ khóa go theo sau là lệnh gọi hàm.

Ví dụ

go add(x,y)

Bạn sẽ hiểu goroutines với các ví dụ về Golang bên dưới. Thực hiện chương trình dưới đây

package main
import "fmt"
    
func display() {
	for i:=0; i<5; i++ {
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	//The main() continues without waiting for display()
	for i:=0; i<5; i++ {
		fmt.Println("In main")
	}
}

Đầu ra sẽ là

In main
In main
In main
In main
In main

Ở đây chương trình chính đã hoàn thành việc thực thi ngay cả trước khi goroutine bắt đầu. display() là một goroutine được gọi bằng cú pháp

go function_name(parameter list)

Trong đoạn mã trên, main() không đợi display() hoàn thành và main() đã hoàn thành việc thực thi trước khi display() thực thi mã của nó. Vì vậy câu lệnh in bên trong display() không được in ra.

Bây giờ chúng ta sửa đổi chương trình để in các câu lệnh từ display(). Chúng tôi thêm độ trễ thời gian là 2 giây trong vòng lặp for của main() và độ trễ 1 giây trong vòng lặp for của display().

package main
import "fmt"
import "time"
    
func display() {
	for i:=0; i<5; i++ {
		time.Sleep(1 * time.Second)
		fmt.Println("In display")
	}
}

func main() {
	//invoking the goroutine display()
	go display()
	for i:=0; i<5; i++ {
		time.Sleep(2 * time.Second)
		fmt.Println("In main")
	}
}

Đầu ra sẽ hơi giống với

In display
In main
In display
In display
In main
In display
In display
In main
In main
In main

Tại đây Bạn có thể thấy cả hai vòng lặp đang được thực thi theo kiểu chồng chéo do thực thi đồng thời.

Các kênh

Kênh là một cách để các chức năng giao tiếp với nhau. Nó có thể được coi là phương tiện để một quy trình đặt dữ liệu và được truy cập bởi một quy trình khác trong máy chủ Golang.

Một kênh có thể được khai báo bằng cú pháp

channel_variable := make(chan datatype)

Ví dụ:

	ch := make(chan int)

Bạn có thể gửi dữ liệu đến một kênh bằng cú pháp

channel_variable <- variable_name

Ví dụ

    ch <- x

Bạn có thể nhận dữ liệu từ một kênh bằng cú pháp

    variable_name := <- channel_variable

Ví dụ

   y := <- ch

Trong các ví dụ về ngôn ngữ Go của goroutine ở trên, bạn đã thấy chương trình chính không chờ goroutine. Nhưng đó không phải là trường hợp khi các kênh có liên quan. Giả sử nếu một goroutine đẩy dữ liệu vào kênh, hàm main() sẽ đợi câu lệnh nhận dữ liệu kênh cho đến khi nhận được dữ liệu.

Bạn sẽ thấy điều này trong các ví dụ về ngôn ngữ Go bên dưới. Đầu tiên, viết một goroutine bình thường và xem hành vi. Sau đó sửa đổi chương trình để sử dụng các kênh và xem hành vi.

Thực hiện chương trình dưới đây

package main
import "fmt"
import "time"
    
func display() {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
}

func main() {
	go display()
	fmt.Println("Inside main()")
}

Đầu ra sẽ là

Inside main()

Main() đã hoàn tất quá trình thực thi và thoát trước khi goroutine thực thi. Vì vậy bản in bên trong display() không được thực thi.

Bây giờ hãy sửa đổi chương trình trên để sử dụng các kênh và xem hành vi.

package main
import "fmt"
import "time"
    
func display(ch chan int) {
	time.Sleep(5 * time.Second)
	fmt.Println("Inside display()")
	ch <- 1234
}

func main() {
	ch := make(chan int) 
	go display(ch)
	x := <-ch
	fmt.Println("Inside main()")
	fmt.Println("Printing x in main() after taking from channel:",x)
}

Đầu ra sẽ là

Inside display()
Inside main()
Printing x in main() after taking from channel: 1234

Ở đây những gì xảy ra là main() khi đạt x := <-ch sẽ đợi dữ liệu trên kênh ch. Display() chờ 5 giây rồi đẩy dữ liệu sang kênh ch. Hàm main() khi nhận dữ liệu từ kênh sẽ được bỏ chặn và tiếp tục thực hiện.

Người gửi đẩy dữ liệu vào kênh có thể thông báo cho người nhận rằng sẽ không có thêm dữ liệu nào được thêm vào kênh bằng cách đóng kênh. Điều này chủ yếu được sử dụng khi bạn sử dụng vòng lặp để đẩy dữ liệu đến một kênh. Một kênh có thể được đóng bằng cách sử dụng

close(channel_name)

Và ở đầu thu, có thể kiểm tra xem kênh có bị đóng hay không bằng cách sử dụng một biến bổ sung trong khi tìm nạp dữ liệu từ kênh bằng cách sử dụng

variable_name, status := <- channel_variable

Nếu trạng thái là True thì có nghĩa là bạn đã nhận được dữ liệu từ kênh. Nếu sai, điều đó có nghĩa là bạn đang cố đọc từ một kênh đã đóng

Bạn cũng có thể sử dụng các kênh để liên lạc giữa các goroutine. Cần sử dụng 2 goroutines – một đẩy dữ liệu vào kênh và một nhận dữ liệu từ kênh. Xem chương trình dưới đây

package main
import "fmt"
import "time"

//This subroutine pushes numbers 0 to 9 to the channel and closes the channel
func add_to_channel(ch chan int) {	
	fmt.Println("Send data")
	for i:=0; i<10; i++ {
		ch <- i //pushing data to channel
	}
	close(ch) //closing the channel

}

//This subroutine fetches data from the channel and prints it.
func fetch_from_channel(ch chan int) {
	fmt.Println("Read data")
	for {
		//fetch data from channel
x, flag := <- ch

		//flag is true if data is received from the channel
//flag is false when the channel is closed
if flag == true {
			fmt.Println(x)
		}else{
			fmt.Println("Empty channel")
			break	
		}	
	}
}

func main() {
	//creating a channel variable to transport integer values
	ch := make(chan int)

	//invoking the subroutines to add and fetch from the channel
	//These routines execute simultaneously
	go add_to_channel(ch)
	go fetch_from_channel(ch)

	//delay is to prevent the exiting of main() before goroutines finish
	time.Sleep(5 * time.Second)
	fmt.Println("Inside main()")
}

Ở đây có 2 chương trình con, một chương trình đẩy dữ liệu vào kênh và chương trình kia in dữ liệu ra kênh. Hàm add_to_channel thêm các số từ 0 đến 9 và đóng kênh. Đồng thời chức năng tìm nạp_from_channel chờ tại

x, flag := <- ch và khi dữ liệu có sẵn, nó sẽ in dữ liệu. Nó thoát khi cờ sai có nghĩa là kênh đã bị đóng.

Sự chờ đợi trong main() được đưa ra để ngăn việc thoát khỏi main() cho đến khi goroutines hoàn thành việc thực thi.

Thực thi mã và xem đầu ra là

Read data
Send data
0
1
2
3
4
5
6
7
8
9
Empty channel
Inside main()

Chọn

Chọn có thể được xem dưới dạng câu lệnh chuyển đổi hoạt động trên các kênh. Ở đây các báo cáo trường hợp sẽ là một hoạt động kênh. Thông thường, mỗi báo cáo trường hợp sẽ được đọc thử từ kênh. Khi bất kỳ trường hợp nào đã sẵn sàng (kênh được đọc), thì câu lệnh liên quan đến trường hợp đó sẽ được thực thi. Nếu nhiều trường hợp đã sẵn sàng, nó sẽ chọn một trường hợp ngẫu nhiên. Bạn có thể có một trường hợp mặc định được thực thi nếu không có trường hợp nào sẵn sàng.

Hãy xem đoạn mã dưới đây

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)
    
    //Both case statements wait for data in the chan1 or chan2.
    //chan2 gets data first since the delay is only 2 sec in data2().
    //So the second case will execute and exits the select block
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    }
}

Thực hiện chương trình trên sẽ cho kết quả:

from data2()

Ở đây câu lệnh chọn chờ dữ liệu có sẵn ở bất kỳ kênh nào. data2() thêm dữ liệu vào kênh sau 2 giây tạm dừng, điều này sẽ khiến trường hợp thứ hai được thực thi.

Thêm trường hợp mặc định vào phần chọn trong cùng một chương trình và xem kết quả. Ở đây, khi tiếp cận khối chọn, nếu không có trường hợp nào có sẵn dữ liệu trên kênh, nó sẽ thực thi khối mặc định mà không cần đợi dữ liệu có sẵn trên bất kỳ kênh nào.

package main
import "fmt"
import "time"

//push data to channel with a 4 second delay
func data1(ch chan string) {  
    time.Sleep(4 * time.Second)
    ch <- "from data1()"
}

//push data to channel with a 2 second delay
func data2(ch chan string) {  
    time.Sleep(2 * time.Second)
    ch <- "from data2()"
}

func main() {
    //creating channel variables for transporting string values  
    chan1 := make(chan string)
    chan2 := make(chan string)
    
    //invoking the subroutines with channel variables
    go data1(chan1)
    go data2(chan2)

    //Both case statements check for data in chan1 or chan2.
    //But data is not available (both routines have a delay of 2 and 4 sec)
    //So the default block will be executed without waiting for data in channels.
    select {
    case x := <-chan1:
        fmt.Println(x)
    case y := <-chan2:
        fmt.Println(y)
    default:
    	fmt.Println("Default case executed")
    }
}

Chương trình này sẽ cho đầu ra:

Default case executed			

Điều này là do khi đạt đến khối chọn, không có kênh nào có dữ liệu để đọc. Vì vậy, trường hợp mặc định được thực thi.

đột biến

Mutex là dạng viết tắt của loại trừ lẫn nhau. Mutex được sử dụng khi bạn không muốn cho phép nhiều chương trình con truy cập tài nguyên cùng một lúc. Mutex có 2 phương pháp – Khóa và Mở khóa. Mutex được chứa trong gói đồng bộ. Vì vậy, bạn phải nhập gói đồng bộ hóa. Các câu lệnh phải được thực thi riêng biệt lẫn nhau có thể được đặt bên trong mutex.Lock() và mutex.Unlock().

Hãy cùng tìm hiểu mutex với một ví dụ đếm số lần một vòng lặp được thực thi. Trong chương trình này, chúng tôi mong đợi quy trình chạy vòng lặp 10 lần và tổng số được lưu trữ. Bạn gọi quy trình này 3 lần nên tổng số sẽ là 30. Số được lưu trong biến toàn cục count.

Đầu tiên bạn chạy chương trình không cần mutex

package main
import "fmt"
import "time"
import "strconv"
import "math/rand"
//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Xem kết quả

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

Kết quả có thể khác khi bạn thực hiện nhưng kết quả cuối cùng sẽ không là 30.

Ở đây điều xảy ra là 3 goroutines đang cố gắng tăng số lượng vòng lặp được lưu trữ trong biến count. Giả sử tại một thời điểm số lượng là 5 và goroutine1 sẽ tăng số lượng lên 6. Các bước chính bao gồm

Sao chép số đếm sang nhiệt độ

Tăng nhiệt độ

Lưu trữ nhiệt độ trở lại để đếm

Giả sử ngay sau khi thực hiện bước 3 bằng goroutine1; một goroutine khác có thể có giá trị cũ, giả sử 3 thực hiện các bước trên và lưu lại 4, điều này là sai. Điều này có thể được ngăn chặn bằng cách sử dụng mutex, khiến các quy trình khác phải chờ khi một quy trình đã sử dụng biến đó.

Bây giờ bạn sẽ chạy chương trình với mutex. Ở đây, 3 bước nêu trên được thực hiện trong một mutex.

package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"

//declare a mutex instance
var mu sync.Mutex

//declare count variable, which is accessed by all the routine instances
var count = 0

//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
	//loop incrementing the count by 10
	for i := 0; i < 10; i++ {
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		//lock starts here
		mu.Lock()
		temp := count
		temp++
		time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
		count = temp
		//lock ends here
		mu.Unlock()
	}
	fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}

func main() {
	//loop calling the process() 3 times
	for i := 1; i < 4; i++ {
		go process(i)
	}

	//delay to wait for the routines to complete
	time.Sleep(25 * time.Second)
	fmt.Println("Final Count:", count)
}

Bây giờ đầu ra sẽ là

 Count after i=3 Count: 21
Count after i=2 Count: 28
Count after i=1 Count: 30
Final Count: 30

Ở đây chúng tôi nhận được kết quả mong đợi là đầu ra cuối cùng. Bởi vì các câu lệnh đọc, tăng và ghi lại số đếm được thực thi trong một mutex.

Xử lý lỗi

Lỗi là các tình trạng bất thường như đóng một tệp chưa được mở, mở một tệp không tồn tại, v.v. Các hàm thường trả về lỗi là giá trị trả về cuối cùng.

Ví dụ dưới đây giải thích thêm về lỗi.

package main
import "fmt"
import "os"

//function accepts a filename and tries to open it.
func fileopen(name string) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        fmt.Println(er)
        return
    }else{
    	fmt.Println("file opened", f.Name())
    }
}

func main() {  
    fileopen("invalid.txt")
}

Đầu ra sẽ là:

open /invalid.txt: no such file or directory

Ở đây chúng tôi đã cố mở một tệp không tồn tại và nó trả về lỗi cho biến er. Nếu tệp hợp lệ thì lỗi sẽ là null

Lỗi tùy chỉnh

Sử dụng tính năng này, bạn có thể tạo ra các lỗi tùy chỉnh. Điều này được thực hiện bằng cách sử dụng gói lỗi New(). Chúng ta sẽ viết lại chương trình trên để tận dụng các lỗi tùy chỉnh.

Chạy chương trình dưới đây

package main
import "fmt"
import "os"
import "errors"

//function accepts a filename and tries to open it.
func fileopen(name string) (string, error) {
    f, er := os.Open(name)

    //er will be nil if the file exists else it returns an error object  
    if er != nil {
        //created a new error object and returns it  
        return "", errors.New("Custom error message: File name is wrong")
    }else{
    	return f.Name(),nil
    }
}

func main() {  
    //receives custom error or nil after trying to open the file
    filename, error := fileopen("invalid.txt")
    if error != nil {
        fmt.Println(error)
    }else{
    	fmt.Println("file opened", filename)
    }  
}

Đầu ra sẽ là:

Custom error message:File name is wrong

Ở đây vùng() trả về diện tích của hình vuông. Nếu đầu vào nhỏ hơn 1 thì vùng() trả về thông báo lỗi.

Đọc tệp

Các tập tin được sử dụng để lưu trữ dữ liệu. Go cho phép chúng ta đọc dữ liệu từ file

Trước tiên hãy tạo một tệp, data.txt, trong thư mục hiện tại của bạn với nội dung bên dưới.

Line one
Line two
Line three

Bây giờ hãy chạy chương trình bên dưới để xem nó in nội dung của toàn bộ tệp dưới dạng đầu ra

package main
import "fmt"
import "io/ioutil"

func main() {  
    data, err := ioutil.ReadFile("data.txt")
    if err != nil {
        fmt.Println("File reading error", err)
        return
    }
    fmt.Println("Contents of file:", string(data))
}

Ở đây dữ liệu, err := ioutil.ReadFile(“data.txt”) đọc dữ liệu và trả về một chuỗi byte. Trong khi in nó được chuyển đổi sang định dạng chuỗi.

Viết tập tin

Bạn sẽ thấy điều này với một chương trình

package main
import "fmt"
import "os"

func main() {  
    f, err := os.Create("file1.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString("Write Line one")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

Ở đây một tập tin được tạo ra, test.txt. Nếu tệp đã tồn tại thì nội dung của tệp sẽ bị cắt bớt. Writeline() được sử dụng để ghi nội dung vào file. Sau đó, bạn đóng tệp bằng Close().

Cheat Sheet

Trong hướng dẫn Go này, chúng tôi đã đề cập đến,

Đề tài Mô tả cú pháp
Các loại cơ bản Số, chuỗi, bool
Biến Khai báo và gán giá trị cho biến loại tên biến var
var biến_name loại = giá trị
var biến_name1, biến_name2 = value1, value2
tên biến := giá trị
Hằng số Các biến có giá trị không thể thay đổi sau khi được gán biến const = giá trị
Đối với vòng lặp Thực hiện các câu lệnh trong một vòng lặp. để khởi tạo_biểu thức; đánh giá_biểu thức; iteration_biểu thức{
// một hoặc nhiều câu lệnh
}
Nếu khác Đó là một câu lệnh có điều kiện nếu điều kiện {
// câu lệnh_1
} Khác {
// câu lệnh_2
}
chuyển đổi Câu lệnh có điều kiện với nhiều trường hợp biểu thức chuyển đổi {
giá trị trường hợp_1:
câu lệnh_1
giá trị trường hợp_2:
câu lệnh_2
giá trị trường hợp_n:
báo cáo_n
mặc định:
câu lệnh_mặc định
}
Mảng Kích thước cố định được đặt tên theo chuỗi các phần tử cùng loại tên mảng := [size] gõ {value_0,value_1,…,value_size-1}
Slice Một phần hoặc phân đoạn của một mảng var slice_name [] type = array_name[start:end]
Chức năng Khối câu lệnh thực hiện một nhiệm vụ cụ thể func function_name(loại tham số_1, loại tham số_n) return_type {
//các câu lệnh
}
Gói Được sử dụng để tổ chức mã. Tăng khả năng đọc mã và khả năng sử dụng lại gói nhập_nam
Hoãn lại Trì hoãn việc thực thi một hàm cho đến khi hàm chứa kết thúc việc thực thi trì hoãn function_name(parameter_list)
con trỏ Lưu trữ địa chỉ bộ nhớ của một biến khác. var biến_name *loại
Structure Kiểu dữ liệu do người dùng xác định, bản thân nó chứa thêm một phần tử cùng loại hoặc khác loại gõ tên cấu trúc struct {
biến_1 biến_1_type
biến_2 biến_2_type
biến_n biến_n_type
}
Phương pháp Một phương thức là một hàm có đối số người nhận func (loại biến biến) tên phương thức(parameter_list) {
}
con khỉ đột Một chức năng có thể chạy đồng thời với các chức năng khác. đi function_name(parameter_list)
Kênh Cách để các chức năng giao tiếp với nhau. Một phương tiện mà một quy trình đặt dữ liệu vào đó và được một quy trình khác truy cập. Khai báo:
ch := make(chan int)
Gửi dữ liệu tới kênh:
kênh_variable <- biến_name
Nhận từ kênh:
tên_biến := <-channel_variable
Chọn Câu lệnh chuyển đổi hoạt động trên các kênh. Các báo cáo trường hợp sẽ là một hoạt động kênh. Khi bất kỳ kênh nào đã sẵn sàng với dữ liệu thì câu lệnh liên quan đến trường hợp đó sẽ được thực thi lựa chọn {
trường hợp x := <-chan1:
fmt.Println(x)
trường hợp y := <-chan2:
fmt.Println(y)
}
đột biến Mutex được sử dụng khi bạn không muốn cho phép nhiều chương trình con truy cập tài nguyên cùng một lúc. Mutex có 2 phương pháp – Khóa và Mở khóa mutex.Lock()
//các câu lệnh
mutex.Unlock().
Đọc tập tin Đọc dữ liệu và trả về một chuỗi byte. Dữ liệu, lỗi := ioutil.ReadFile(filename)
Viết tập tin Ghi dữ liệu vào một tập tin l, err := f.WriteString(text_to_write)