Menu
CoddyTech

encoding/json với struct

Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 76 trên 107.

Package encoding/json giúp bạn chuyển đổi struct của Go sang JSON và ngược lại. Đây là điều thiết yếu khi làm việc với API, tệp cấu hình và lưu trữ dữ liệu. Struct tag kiểm soát cách các trường ánh xạ sang khóa JSON.

Để chuyển đổi một struct sang JSON, hãy dùng json.Marshal:

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

func main() {
    user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
    data, _ := json.Marshal(user)
    fmt.Println(string(data))
    // {"name":"Alice","email":"alice@example.com","age":30}
}

Các thẻ struct như `json:"name"` chỉ định tên khóa JSON. Nếu không có thẻ, Go dùng trực tiếp tên trường. Chỉ các trường được xuất (viết hoa chữ cái đầu) mới có trong đầu ra JSON.

Để chuyển JSON trở lại thành một struct, hãy dùng json.Unmarshal:

jsonStr := `{"name":"Bob","email":"bob@example.com","age":25}`
var user User
json.Unmarshal([]byte(jsonStr), &user)
fmt.Println(user.Name)  // Bob

Các tùy chọn tag thường dùng gồm omitempty để bỏ qua giá trị không và - để hoàn toàn bỏ qua một trường:

type Product struct {
    ID       int    `json:"id"`
    Name     string `json:"name"`
    Price    float64 `json:"price,omitempty"`
    Internal string `json:"-"`
}

Với omitempty, nếu Price bằng 0, trường này sẽ không xuất hiện trong JSON. Trường Internal không bao giờ được đưa vào, bất kể giá trị của nó là gì.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống danh mục phim có thể chuyển đổi giữa struct của Go và JSON! Bạn sẽ luyện tập cách marshal struct thành JSON và unmarshal JSON trở lại thành struct, đồng thời dùng thẻ struct để kiểm soát tên trường JSON.

Bạn sẽ sắp xếp code trong hai tệp:

  • movie.go: Định nghĩa mô hình dữ liệu phim với các thẻ JSON phù hợp.

    Tạo một struct Movie với các trường và ánh xạ JSON sau:

    • Title (string) ánh xạ thành "title"
    • Director (string) ánh xạ thành "director"
    • Year (int) ánh xạ thành "year"
    • Rating (float64) ánh xạ thành "rating" với omitempty để phim chưa được đánh giá không hiển thị trường rating
    • InternalID (string) phải được loại khỏi JSON hoàn toàn bằng cách dùng "-"

    Tạo một hàm (function) ToJSON(m Movie) string để chuyển một Movie thành chuỗi JSON. Đồng thời tạo FromJSON(jsonStr string) Movie để phân tích chuỗi JSON và chuyển thành struct Movie.

  • main.go: Minh họa cách chuyển đổi JSON theo cả hai chiều.

    Đọc loại thao tác (encode hoặc decode).

    Với encode: Đọc thông tin phim (title, director, year, rating), mỗi thông tin trên một dòng riêng. Tạo một Movie có InternalID là "internal-123", chuyển thành JSON rồi in kết quả ra.

    Với decode: Đọc một chuỗi JSON, chuyển thành struct Movie rồi in thông tin phim theo định dạng sau:

    Title: [title]
    Director: [director]
    Year: [year]
    Rating: [rating]

    Hiển thị rating với một chữ số thập phân. Nếu rating là 0 (không có trong JSON), hãy in Rating: N/A.

Đầu vào sẽ có định dạng sau:

  • Dòng 1: Loại thao tác (encode hoặc decode)
  • Với encode: title, director, year, rating (bốn dòng)
  • Với decode: một chuỗi JSON (một dòng)

Ví dụ, với đầu vào:

encode
Inception
Christopher Nolan
2010
8.8

Kết quả đầu ra sẽ là:

{"title":"Inception","director":"Christopher Nolan","year":2010,"rating":8.8}

Lưu ý rằng InternalID không xuất hiện trong đầu ra vì có thẻ "-".

Với đầu vào:

encode
The Matrix
Wachowskis
1999
0

Kết quả đầu ra sẽ là:

{"title":"The Matrix","director":"Wachowskis","year":1999}

Lưu ý rằng rating bị lược bỏ vì giá trị bằng 0 và có omitempty.

Với đầu vào:

decode
{"title":"Interstellar","director":"Christopher Nolan","year":2014,"rating":8.6}

Kết quả đầu ra sẽ là:

Title: Interstellar
Director: Christopher Nolan
Year: 2014
Rating: 8.6

Với đầu vào:

decode
{"title":"Tenet","director":"Christopher Nolan","year":2020}

Kết quả đầu ra sẽ là:

Title: Tenet
Director: Christopher Nolan
Year: 2020
Rating: N/A

Tự làm thử

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Đọc loại thao tác
	operation, _ := reader.ReadString('\n')
	operation = strings.TrimSpace(operation)

	if operation == "encode" {
		// Đọc thông tin phim
		title, _ := reader.ReadString('\n')
		title = strings.TrimSpace(title)

		director, _ := reader.ReadString('\n')
		director = strings.TrimSpace(director)

		yearStr, _ := reader.ReadString('\n')
		yearStr = strings.TrimSpace(yearStr)
		year, _ := strconv.Atoi(yearStr)

		ratingStr, _ := reader.ReadString('\n')
		ratingStr = strings.TrimSpace(ratingStr)
		rating, _ := strconv.ParseFloat(ratingStr, 64)

		// TODO: Tạo struct Movie với các giá trị đã đọc
		// Đặt InternalID thành "internal-123"
		// Dùng ToJSON để chuyển sang JSON và in kết quả

	} else if operation == "decode" {
		// Đọc chuỗi JSON
		jsonStr, _ := reader.ReadString('\n')
		jsonStr = strings.TrimSpace(jsonStr)

		// TODO: Dùng FromJSON để chuyển JSON thành Movie
		// In thông tin phim theo định dạng yêu cầu
		// Dùng fmt.Sprintf("%.1f", rating) để định dạng rating
		// Nếu rating bằng 0, hãy in "Rating: N/A" thay thế

	}
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Go online