خطوط لاگ

خطوط لاگ

تمرین یادگیری

مقدمه

وقتی می‌خواهید داده‌ای را مدل‌سازی کنید که فقط می‌تواند مجموعه‌ی مشخصی از حالت‌های ممکن را بپذیرد، مثل روزهای هفته، جهت‌های قطب‌نما یا دکمه‌های یک دسته‌بازی، انواع پایه‌ای مثل Int یا String اشکالات بزرگی دارند. با عددهای صحیح یا رشته‌ها، کد شما باید مدام مقادیر نامعتبر را بررسی کند (مثلاً کد وضعیتی برابر با 999 یا غلط تایپی مثل "leftt")، و خوانندگان انسانی هم به‌سختی می‌توانند بفهمند این اعداد چه چیزی را نشان می‌دهند.

Swift این مشکل را با شمارشی حل می‌کند (که اغلب به enum کوتاه می‌شود). شمارشی یک نوع مشترک برای گروهی از مقادیر نام‌دار و مرتبط تعریف می‌کند. چون کامپایلر از پیش همه‌ی حالت‌های ممکن را می‌داند، می‌تواند کد شما را در زمان کامپایل از نظر درستی و کامل بودن بررسی کند. شمارشی‌ها می‌توانند متد، سازنده و ویژگی‌های محاسبه‌شده هم داشته باشند.

تعریف شمارشی

برای تعریف یک شمارشی از کلیدواژه‌ی enum و بعد از آن اسم نوع استفاده کنید و حالت‌هایش را داخل آکولاد فهرست کنید. طبق قرارداد Swift، اسم نوع با UpperCamelCase نوشته می‌شود و هر حالت با lowerCamelCase:

enum NESButton {
    case up
    case down
    case left
    case right
    case a
    case b
    case select
    case start
}

می‌توانید چندین حالت را هم در یک خط و جدا‌شده با کاما تعریف کنید:

enum NESButton {
    case up, down, left, right, a, b, select, start
}

برای اشاره به یک حالت شمارشی، اسم نوع شمارشی را بنویسید و بعد از آن یک نقطه (.) و سپس اسم حالت را بیاورید. وقتی نوع معلوم باشد یا کامپایلر بتواند آن را استنتاج کند، می‌توانید اسم نوع را حذف کنید و از روش نوشتن کوتاه‌تر با نقطه استفاده کنید:

var lastPressed = NESButton.up

// Swift infers the type, so you can omit the type name:
lastPressed = .down

let konamiCode: [NESButton] = [.up, .up, .down, .down, .left, .right, .left, .right, .b, .a]

متد و سازنده

شمارشی‌ها می‌توانند درست مثل کلاس‌ها و ساختارها متد و سازنده‌ی سفارشی تعریف کنند. داخل یک متد شمارشی، self به مقدار حالت جاری اشاره می‌کند:

enum Coin {
    case heads
    case tails

    init(_ value: Int) {
        if value.isMultiple(of: 2) {
            self = .heads
        } else {
            self = .tails
        }
    }

    func flip() -> Coin {
        switch self {
        case .heads: return .tails
        case .tails: return .heads
        }
    }
}

let tails = Coin(13)     // .tails
let heads = Coin(0)      // .heads
let flipped = heads.flip() // .tails

مقادیر خام

حالت‌های یک شمارشی می‌توانند با مقادیر پیش‌فرضی به نام مقادیر خام از پیش پر شوند. همه‌ی مقادیر خام در یک شمارشی باید از یک نوع باشند (مثل Int، String یا Character):

enum NESButton: Character {
    case up = "⬆️"
    case down = "⬇️"
    case left = "⬅️"
    case right = "➡️"
    case a = "🅰️"
    case b = "🅱️"
    case select = "✅"
    case start = "🚦"
}

print(NESButton.left.rawValue) // Prints "⬅️"

می‌توانید یک شمارشی را با init(rawValue:) از یک مقدار خام بسازید. چون ممکن است مقدار خامی نامعتبر داده شود، این سازنده یک مقدار اختیاری برمی‌گرداند:

let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄")  // nil

Swift می‌تواند برای شمارشی‌های String و Int به‌طور خودکار مقادیر خام تعیین کند:

  • در شمارشی‌های String، مقدار خام هر حالت به‌طور پیش‌فرض اسم همان حالت است.
  • در شمارشی‌های Int، مقادیر خام از 0 شروع می‌شوند و تا وقتی خلاف آن مشخص نشده باشد، هر بار یک واحد زیاد می‌شوند.
enum Planet: Int {
    case mercury = 1, venus, earth, mars
}

print(Planet.earth.rawValue) // Prints 3

دستورالعمل‌ها

در این تمرین، خط‌های لاگ را پردازش می‌کنید.

هر خط لاگ رشته‌ای است با قالب زیر: "[<LVL>]: <MESSAGE>".

این‌ها سطوح مختلف لاگ هستند:

  • TRC (trace)
  • DBG (debug)
  • INF (info)
  • WRN (warning)
  • ERR (error)
  • FTL (fatal)

سه وظیفه دارید و باید هر سه را انجام دهید تا قابلیت لازم فراهم شود.

1. ساخت enum به اسم LogLevel

یک enum به اسم LogLevel تعریف کنید که شش حالت متناظر با سطوح لاگ بالا دارد، به همراه یک حالت unknown برای سطح‌هایی که ناموجود یا غیراستاندارد هستند.

  • trace
  • debug
  • info
  • warning
  • error
  • fatal
  • unknown

2. تجزیه‌ی سطح لاگ

سپس، سازنده‌ی LogLevel را پیاده‌سازی کنید تا سطح لاگ یک خط لاگ را تجزیه کند:

LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown

3. تبدیل خط لاگ به قالب کوتاه

سطح لاگ یک خط لاگ بسیار طولانی است. برای کاهش فضای دیسک لازم برای ذخیره‌ی خط‌های لاگ، یک قالب کوتاه طراحی شده است: "<ENCODED_LEVEL>:<MESSAGE>".

سطح لاگ رمزگذاری‌شده نگاشتی ساده از سطح لاگ به یک عدد است:

  • trace - 0
  • debug - 1
  • info - 4
  • warning - 5
  • error - 6
  • fatal - 7
  • unknown - 42

متد shortFormat(message: String) -> String را پیاده‌سازی کنید که می‌تواند قالب کوتاه‌شده‌ی خط لاگ را به‌صورت یک String خروجی بدهد:

let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Swift Exercism

آماده‌اید خطوط لاگ را شروع کنید؟

در Exercism ثبت‌نام کنید تا Swift را همراه با 35 مفهوم116 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.