Menu
CoddyTech

Ô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.

challenge icon

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à:

  1. Tạo hai kiểu lỗi tùy chỉnh:
    • Cấu trúc DivisionError có các trường Dividend (float64) và Divisor (float64)
    • Cấu trúc ValidationError có các trường Field (string) và Value (float64)
  2. Triển khai phương thức Error() string cho DivisionError, trả về: "division error: cannot divide [dividend] by [divisor]"
  3. Triển khai phương thức Error() string cho ValidationError, trả về: "validation error: invalid [field] value [value]"
  4. 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
  5. 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ế độ
  6. Chuyển các số dạng chuỗi thành float64 và precision thành int
  7. Tạo hàm safeDivide nhận hai tham số float64 và trả về (float64, error):
    • Nếu divisor bằng 0, trả về 0 và một lỗi DivisionError chứ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ỗi ValidationError có 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ỗi ValidationError có trường "divisor" cùng giá trị divisor
    • Nếu không, trả về kết quả phép chia và nil
  8. Tạo hàm performCalculation để bọc kết quả của safeDivide:
    • Nếu safeDivide trả 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
  9. Gọi performCalculation và 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]"
  10. 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]"
  11. Nếu tìm thấy lỗi DivisionError, in thông tin chi tiết:
    • "Division Error Details:"
    • "Dividend: [dividend]"
    • "Divisor: [divisor]"
  12. Nếu tìm thấy lỗi ValidationError, in thông tin chi tiết:
    • "Validation Error Details:"
    • "Field: [field]"
    • "Value: [value]"
  13. 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

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