Ôn tập: phép chia an toàn
Thuộc phần Logic và luồng điều khiển trong hành trình GO của Coddy. Bài học 44 trên 68.
Thử thách
DễHãy xây dựng một máy tính toán học toàn diện có phép chia an toàn, nhiều kiểu lỗi tùy chỉnh và khả năng xử lý lỗi phù hợp. Thử thách này kết hợp các kiểu lỗi tùy chỉnh, bọc lỗi và kiểm tra lỗi để tạo một hệ thống mạnh mẽ, xử lý ổn thỏa nhiều lỗi phép toán khác nhau.
Bạn sẽ nhận được hai đầu vào:
- Một chuỗi chứa thông tin phép toán theo định dạng
"operation,num1,num2,precision"(ví dụ:"divide,10,0,2") - Một chuỗi chứa các cài đặt của máy tính theo định dạng
"calculator_name,mode"(ví dụ:"ScientificCalc,strict")
Nhiệm vụ của bạn là:
- Tạo hai kiểu lỗi tùy chỉnh:
- Cấu trúc
DivisionErrorcó các trườngDividend(float64) vàDivisor(float64) - Cấu trúc
ValidationErrorcó các trườngField(string) vàValue(float64)
- Cấu trúc
- Triển khai phương thức
Error() stringchoDivisionError, trả về:"division error: cannot divide [dividend] by [divisor]" - Triển khai phương thức
Error() stringchoValidationError, trả về:"validation error: invalid [field] value [value]" - Phân tích đầu vào thứ nhất bằng cách tách chuỗi theo dấu phẩy để lấy operation, num1, num2 và precision
- Phân tích đầu vào thứ hai bằng cách tách chuỗi theo dấu phẩy để lấy tên máy tính và chế độ
- Chuyển các số dạng chuỗi thành float64 và precision thành int
- Tạo hàm
safeDividenhận hai tham số float64 và trả về (float64, error):- Nếu divisor bằng 0, trả về 0 và một lỗi
DivisionErrorchứa các giá trị dividend và divisor - Nếu dividend là số âm và mode là
"strict", trả về 0 và một lỗiValidationErrorcó trường"dividend"cùng giá trị dividend - Nếu divisor là số âm và mode là
"strict", trả về 0 và một lỗiValidationErrorcó trường"divisor"cùng giá trị divisor - Nếu không, trả về kết quả phép chia và nil
- Nếu divisor bằng 0, trả về 0 và một lỗi
- Tạo hàm
performCalculationđể bọc kết quả củasafeDivide:- Nếu
safeDividetrả về lỗi, bọc lỗi bằng:"calculation failed in [calculator_name]: %w" - Nếu thành công, trả về kết quả và nil
- Nếu
- Gọi
performCalculationvà xử lý kết quả:- Nếu không có lỗi: in ra
"Calculation successful: [result_formatted_to_precision_decimal_places]" - Nếu có lỗi: in ra
"Calculation failed: [error_message]"
- Nếu không có lỗi: in ra
- Dùng
errors.Asđể kiểm tra các kiểu lỗi cụ thể trong lỗi đã được bọc:- In ra
"Checking for division error: [true/false]" - In ra
"Checking for validation error: [true/false]"
- In ra
- Nếu tìm thấy lỗi
DivisionError, in thông tin chi tiết:"Division Error Details:""Dividend: [dividend]""Divisor: [divisor]"
- Nếu tìm thấy lỗi
ValidationError, in thông tin chi tiết:"Validation Error Details:""Field: [field]""Value: [value]"
- Hiển thị bản tóm tắt cuối cùng:
"Calculator Summary:""Name: [calculator_name]""Mode: [mode]""Operation: [operation]""Input: [num1] [operation_symbol] [num2]", trong đó operation_symbol là "/" khi phép toán là chia"Precision: [precision] decimal places""Status: [Success/Failed]"
Dùng package strings để tách các chuỗi đầu vào theo dấu phẩy, package strconv để chuyển chuỗi thành số, package errors cho errors.As và package fmt để bọc và định dạng lỗi. Thử thách này minh họa cách các kiểu lỗi tùy chỉnh, việc bọc lỗi và kiểm tra lỗi phù hợp phối hợp với nhau để tạo hệ thống xử lý lỗi mạnh mẽ, cung cấp thông tin chi tiết về nhiều kiểu lỗi khác nhau.
Tự làm thử
package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
func main() {
// Đọc đầu vào
var operationInput string
var settingsInput string
fmt.Scanln(&operationInput)
fmt.Scanln(&settingsInput)
// Phân tích đầu vào của phép tính (operation,num1,num2,precision)
operationParts := strings.Split(operationInput, ",")
operation := operationParts[0]
num1, _ := strconv.ParseFloat(operationParts[1], 64)
num2, _ := strconv.ParseFloat(operationParts[2], 64)
precision, _ := strconv.Atoi(operationParts[3])
// Phân tích đầu vào của phần cài đặt (calculator_name,mode)
settingsParts := strings.Split(settingsInput, ",")
calculatorName := settingsParts[0]
mode := settingsParts[1]
// TODO: Viết code bên dưới
// 1. Tạo các struct DivisionError và ValidationError với phương thức Error()
// 2. Triển khai hàm safeDivide
// 3. Triển khai hàm performCalculation
// 4. Gọi performCalculation và xử lý kết quả
// 5. Dùng errors.As để kiểm tra các kiểu lỗi cụ thể
// 6. In chi tiết lỗi nếu có
// 7. Hiển thị phần tổng kết cuối cùng
}Tất cả bài học trong Logic và luồng điều khiển
1Luồng điều khiển nâng cao
Switch với `fallthrough`Thoát khỏi vòng lặp lồng nhauTiếp tục một vòng lặp cụ thểCâu lệnh `goto`Ôn tập: điều khiển vòng lặp nâng cao4Dự án: Danh sách việc cần làm đơn giản
Thiết lập dự ánThêm một việc cần làm7Xử lý lỗi chuyên sâu
Kiểu lỗi tùy chỉnhBọc lỗi bằng `%w`Gỡ bọc lỗi bằng `errors.Is`Gỡ bọc lỗi bằng `errors.As`Tìm hiểu `panic`Sử dụng `recover`Ôn tập: phép chia an toàn2Struct và phương thức
Định nghĩa phương thức cho structReceiver giá trịReceiver con trỏChọn receiverPhương thức và hàmÔn tập: hành vi của struct5Tìm hiểu chuyên sâu về map
Map chứa structCon trỏ làm giá trị của mapKiểm tra map nilSo sánh các mapÔn tập: bộ đếm tần suất từ8Dự án: Quản lý hàng tồn kho đơn giản
Tổng quan dự ánKiểm tra hàng tồn kho3Interface (cơ bản)
Interface là gì?Định nghĩa interfaceTriển khai interfaceDùng kiểu interfaceInterface rỗngKhẳng định kiểuType switchÔn tập: hình dạng và hành viTự luyện tập: Trình biên dịch Go online