Is there a way to use tabs to evenly space out description strings in Swift?

前端 未结 2 1571
北海茫月
北海茫月 2021-01-15 04:21

Overriding the description variable of a custom class:

override var description : String {
        let mirrored_object = Mirror(reflecting: self)
        let         


        
相关标签:
2条回答
  • 2021-01-15 04:30

    I wouldn't use tabs but use padding(...):

    var description : String {
        let mirrored_object = Mirror(reflecting: self)
        let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
        let maxLen = childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0
        let lines = childrenWithLabel.map { $0.label!.padding(toLength: maxLen, withPad: " ", startingAt: 0) + " = \($0.value)" }
        return lines.joined(separator: "\n")
    }
    

    For a struct like

    struct Foo: CustomStringConvertible
    {
        let userID = 42
        let username = "Foo"
        let verylongpropertyname: String? = "Bar"
    }
    

    this produces

    userID               = 42
    username             = Foo
    verylongpropertyname = Optional("Bar")
    

    As for the "Optional" part, it's not as easy as totiG suggests because the value you get from the mirror is of type Any. See this question.

    Update

    I overlooked that you wanted to have a slightly different format.

    var description : String {
        let mirrored_object = Mirror(reflecting: self)
        let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
        let separator = " = "
        let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
        let lines = childrenWithLabel.map {
            ($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\($0.value)"
        }
    }
    

    produces

    userID =               42
    username =             Foo
    verylongpropertyname = Optional("Bar")
    

    Update 2

    To get rid of the "Optional" thing, please see my answer here.

    If you use (from said answer) unwrap() or unwrapUsingProtocol() in description like this:

    var description : String {
        let mirrored_object = Mirror(reflecting: self)
        let childrenWithLabel = mirrored_object.children.filter { $0.label != nil }
        let separator = " = "
        let firstColumnWidth = (childrenWithLabel.map { Int($0.label!.characters.count) }.max() ?? 0) + separator.characters.count
        let lines = childrenWithLabel.map {
            ($0.label! + separator).padding(toLength: firstColumnWidth, withPad: " ", startingAt: 0) + "\(unwrap($0.value))"
        }
        return lines.joined(separator: "\n")
    }
    

    this will produce

    userID =               42
    username =             Foo
    verylongpropertyname = Bar
    
    0 讨论(0)
  • 2021-01-15 04:32

    Try use this method. It first calculates the max length of the property, and then uses that to pad the property names:

    let maxPropertyLength: Int = mirrored_object.children.map { Int($0.label?.characters.count ?? 0) }.max() ?? 0
    for attr in mirrored_object.children {
        if let propertyName = attr.label {
            str.append("\(propertyName.padding(toLength: maxPropertyLength + 2, withPad: " ", startingAt: 0)) = \(attr.value)\n")
        }
    }
    return str as String
    
    0 讨论(0)
提交回复
热议问题