Làm quen với Golang dưới cái nhìn của lập trình viên PHP: PHP -> GO

Làm quen với Golang dưới cái nhìn của lập trình viên PHP: PHP -> GO
Golang

Mình là một người mới chân ướt chân ráo đi vào con đường làm coder, định hướng ban đầu của mình là đi theo php Laravel. Nhưng đường đời không lý tưởng như mà mình đã vẽ ra trước đó, trong thời hơn 1 năm học tập và làm việc với php, mình được lôi kéo (dụ dỗ) đi qua một dự án khác và một ngôn ngữ khác. Lần này mình bị dụ qua code Golang, một ngôn ngữ mà mình chưa từng nghe đến và không hề biết đến sự tồn tại của ngôn ngữ này. Sau một thời gian tìm hiểu thì mình quyết định thử thách bản thân xem khả năng của mình đến đâu, và đoán xem.? Mình đã trở thành 1 fan của Golang, ngôn ngữ đang nằm trong top ngôn ngữ lập trình được ưa thích trong những năm gần đây. Vậy code từ php -> Go có khó hay không và cú pháp của nó như thế nào. Xin mời các bạn theo dõi bài viết này của mình.

Giới thiệu đôi chút về Go

Go hay còn gọi là Golang là ngôn ngữ lập trình mã nguồn mở, được thiết kế tại Google bởi Robert Griesemer, Rob Pike, and Ken Thompson.

Go có cú pháp giống với C và nó là ngôn ngữ lập trình biên dịch (compiled programming language).

Cú pháp của ngôn ngữ lập trình Golang (syntax) khá tinh gọn, mặc dù thật sự có những cú pháp mà người mới nhìn vào thật sự hơi khó chịu. Nhưng tin mình đi, sau một thời gian code với Go thì bạn sẽ trở lên cực kỳ thích với cú pháp của Go.

VD:

package main

import "fmt"

func main() {
    fmt.Println("Ready to GO")
}

Go bắt đầu từ main package và bắt đầu bằng main function, khá giống với C phải không nào. Các package mà không phải là main thì được gọi là các thư viện, các thư viện này có thể thêm từ bên ngoài hoặc mình có thể tự xây dựng. Trên đây là phần giới thiệu tổng quan về Go, các bạn có thể tìm hiểu kỹ hơn bằng cách tra Google. Không dài dòng nữa, đi vào nội dung chính thôi nào.

PHP to Go

Khai báo biến (Variables)

Coder từ PHP hoặc Javascript chuyển qua Go bạn cần chú ý một điều hết sức quan trọng đó là: Go là một ngôn ngữ statically typed vì thế một biến cần phải được khai báo cùng với kiểu dữ liệu của nó.

// PHP
$borned = true;
$age = null;

if ( $borned ) {
    $age = 36;
}
// Go
borned := true
var age bool

if borned {
    age = 36
}

Trong GO có 3 cách để khai báo 1 biến := là một trong số chúng, ngoài ra còn 2 cách khác để khai báo biến như dưới đây

var old bool
old = true

// Or..
var old = true //inferred type

// Or...
old := true
Cách khai báo biến trong Go

Go hỗ trợ hầu hết các kiểu dữ liệu thường sử dụng như: int, string, float (float32, float64), ....

Mảng (Arrays)

Khai báo 1 mảng trong PHP thì rất đơn giản:

//PHP
$dogs = [
    'Pug',
    'Chihuahua',
    'Husky',
    'Pit Bull'
];

Còn với Go:

//Go
dogs := [4]string{
    "Pug",
    "Chihuahua",
    "Husky",
    "Pit Bull",
}

Nhìn cũng đơn giản, nhưng [4]string là cái gì ? Đây là một mảng cố định, trong Go và cũng giống như C. Một mảng sẽ có 1 size cố định, nếu muốn thêm 1 phần tử thứ 5 vào trong mảng thì sao ? Copy và thêm 1 phần tử mới vào ư ? No No !  Lúc này ta sẽ sử dụng slice trong Go, cái này cũng khá giống một mảng động của PHP.

Slices

//Go
dogs := []string{
    "Pug",
    "Chihuahua",
    "Husky",
    "Pit Bull",
}

Nó khác gì với array được khai báo ở bên trên? Bản chất của chúng là như nhau, nhưng slice sẽ không cần khai báo số phần tử cho nó. Slice cũng có độ dài và sức chứa của nó, tương tự như array, nó sẽ tự động tái kích thước nếu mình thêm mình thêm 1 phần tử vào cho nó.

Có thể truy cập vào các phần tử trong slice, dựa vào index tương tự như PHP

fmt.Println(dogs[0]) // Pug
dogs[0] = "Alaska"
fmt.Println(dogs[0]) // Alaska

Trong PHP ta sử dụng array_slice() để cắt phần tử trong mảng, ở Go thì đơn giản hơn, nó sử dụng cú pháp slice[high:low] để cắt.

new_dogs := mah_dogs[2:]
fmt.Println(new_dogs) // Husky, Pit Bull

với low để trống thì slice sẽ cắt từ phần tử thứ 2 đến cuối slice

Cuối cùng, bạn không thể thêm phần tử vào mảng giống với cách mà bạn làm ở PHP, để thêm phần tử vào slice thì ta cần phải sử dụng hàm append()

//PHP
$dogs[] = 'Shiba';
$dogs[] = 'Corgi';

//Go
dogs = append(dogs, "Shiba", "Corgi")

Với slice index bắt buộc phải là integers và bạn không thể thay đổi giá trị của index hay sử dụng string là index giống như PHP, lúc này trong Go sẽ có một khái niệm khác đó là map

Maps

//PHP
$groceries = [
    'bread' => 1.99,
    'milk' => 2.99,
    'eggs' => 4.99,
];

//Go
groceries := map[string]float32{
    "bread" : 1.99,
    "milk" : 2.99,
    "eggs" : 4.99,
}

Cú pháp để khai báo map là: map[key_type]value_type. Cách truy cập đến phần tử trong map thì  cũng tương tự như PHP.

priceOfBread := groceries["bread"]

Cách gán giá trị  cho phần tử trong map cũng giống PHP vậy

groceries["apple"] = 5.99

Không giống như slice, khi muốn thêm một phần tử vào trong map ta có thể sử dụng cách tương tự như bên PHP

groceries["banana"] = 6.99

Vòng lặp (loops)

Với php, coder có thể dùng foreach để duyệt qua từng phần tử trong mảng. Còn ở Go thì sao, hãy quên foreach ở go đi vì Go không có từ khoá nào là foreach cả. Go chỉ hỗ trợ một phương thức lặp duy nhất đó là vòng for

Tuy nhiên, for trong Go vi diệu lắm, nó có thể thay thế cho cả foreach và while trong các ngôn ngữ khác.

for, while trong Go

//For
sum := 0
for i := 0; i < 10; i++ {
    sum += i
}

//While in Go
for sum < 1000 {
    sum += sum
}

Để duyệt các phần tử giống như foreach thì ta sẽ sử dụng range

for key, value := range groceries {
    fmt.Printf("%s costs $%.2f\n", key, value)
}

//Output
bread costs $1.99
milk costs $2.99
eggs costs $4.99

Function trả về nhiều giá trị

Function trong Go cũng tương tự như PHP, nhưng có một vài điều đặc biệt sau.

Để trả về nhiều giá trị từ function, PHP cần phải thêm 1 array và chứa giá trị vào trong nó. Nhưng ở Go, bạn có thể trả về nhiều giá trị từ một func, không cần phải trả về 1 array nữa

//PHP
function getDogs() {
    $dogs = [
        'count' => 4,
        'dogs' => [
            "Pug",
            "Chihuahua",
            "Husky",
            "Pit Bull",
        ]
    ];

    return $dogs;
}
extract(getDogs());

//Go
func getDogs() (count int, dogs []string) {
    count = 4
    dogs = []string{
        "Pug",
        "Chihuahua",
        "Husky",
        "Pit Bull",
    }

    return
}

count, dogs = getDogs()

Ở ví dụ trên, Go sử dụng 1 cách gọi là results (count int, dogs []string), khi return được gọi, thì các giá trị được thay đổi ở trong hàm sẽ được trả về, hoặc bạn cũng có thể sử dụng cách thông thường

//Go
func getDogs() (int, []string) {
    count := 4
    dogs := []string{
        "Pug",
        "Chihuahua",
        "Husky",
        "Pit Bull",
    }

    return count, dogs
}

count, dogs := getDogs()

Vì func getDogs() trả về 2 biến, nên khi gọi đến func này người dùng cũng cần phải tạo 2 biến để chứa giá trị từ hàm trả về. Nếu tôi chỉ muốn lấy 1 trong 2 giá trị và bỏ qua giá trị kia thì sao ?

Lúc này ta có thể sử dụng định danh rỗng của Go, bằng cách sử dụng _, ký tự này giúp bạn có thể bỏ qua giá trị mà bạn không cần dùng đến

_, dogs := getDogs()

Cách viết như này thì giá trị count trả về từ hàm sẽ bị bỏ qua.

Structs

Struct là một thứ giúp bạn có thể sử dụng để làm việc với objects.

Ở PHP chúng ta có class, nó có thể chứa các function và các thuộc tính. Tương tự như bên Go, ta có khái niện struct. Struct đơn giản chỉ là gom nhóm các biến với các kiểu dữ liệu khác nhau.

package main

import (
    "fmt"
    "strings"
)

type dog struct {
    name  string
    age   int
    likes []string
}

func main() {
    goodBoy := dog{"Skinny", 4, []string{"Food", "Sleeping"}}
    fmt.Printf("This is %s. It's age is %d and it's favorite things are %s", goodBoy.name, goodBoy.age, strings.Join(goodBoy.likes, ", "))
}

// Output: This is Skinny. It's age is 4 and it's favorite things are Food, Sleeping

Ví dụ bên trên cho ta thấy, ta có một struct đặt tên là dog, trong dog có 3 trường:

name, age, likeslikes là một mảng chứa nhiều giá trị.

Khi mình muốn tạo dog , có thể sử dụng cái struct vừa khai báo ở bên trên, chỉ cần điền các giá trị cho các trường.

Struct còn có thể làm nhiều hơn nữa. thêm func cho struct, in ra thông tin của dog có thể viết thành 1 hàm của struct như sau:

package main

import (
    "fmt"
    "strings"
)

type dog struct {
    name  string
    age   int
    likes []string
}

func (d dog) printInfo() {
	fmt.Printf("This is %s. It's age is %d and it's favorite things are %s", d.name, d.age, strings.Join(d.likes, ", "))
}

func main() {
    goodBoy := dog{"Skinny", 4, []string{"Food", "Sleeping"}}
    goodBoy.printInfo()
}

Kết

Trên đây là một số kinh nghiệm của mình khi bắt đầu code Go từ PHP, hy vọng với một số chia sẻ ít ỏi như thế này các bạn có thể chuyển qua code Go từ PHP và làm quen Go nhanh chóng.

Hãy thử code Go đi, bạn sẽ thích nó cho mà xem. !!!