Jak mogę zmienić reprezentację tekstową wyświetlaną dla typu w języku Swift?

92

Jak mogę zmodyfikować tekstowe dane wyjściowe, które są wyświetlane w interpolacji ciągów?

PrintableProtokół wygląda najbardziej oczywiste, ale to zignorował zarówno String interpolacji podczas drukowania instancji, np:

struct Point : Printable
{
    var x = 0
    var y = 0

    var description : String {
        return "(\(x), \(y))"
    }

    func toString() -> String {
        return description
    }
}

Podobnie toString()konwencja nie ma żadnego skutku:

var p = Point(x: 10, y: 20)

println(p)                   // V11lldb_expr_05Point (has 2 children)
println("\(p)")              // V11lldb_expr_05Point (has 2 children)
println(p.description)       // (10, 20)
println("\(p.description)")  // (10, 20)

Zachowanie jest znowu inne w PlayGround, który używa własnej reprezentacji String dla struktur, tj .:

p // {x 10, y 20}

Czy istnieje sposób, aby zmienić sposób wyświetlania instancji?

mit
źródło
Powyższy kod działa zgodnie z oczekiwaniami w Playgrounds w Xcode 6.3 beta 4
carbo18

Odpowiedzi:

113

Swift 2-4

Podsumowanie

Zgodność z CustomStringConvertibleprotokołem i dodaj description:

var description: String {
    return "description here"
}

Przykład

Możesz stworzyć kilka struktur:

struct Animal : CustomStringConvertible {
    let type : String

    var description: String {
        return type
    }
}

struct Farm : CustomStringConvertible {
    let name : String
    let animals : [Animal]

    var description: String {
        return "\(name) is a \(self.dynamicType) with \(animals.count) animal(s)."
    }
}

Jeśli je zainicjujesz:

let oldMajor = Animal(type: "Pig")
let boxer = Animal(type: "Horse")
let muriel = Animal(type: "Goat")

let orwellsFarm = Farm(name: "Animal Farm", animals: [oldMajor, boxer, muriel])

Niestandardowe opisy pojawią się na Twoim placu zabaw:

wprowadź opis obrazu tutaj

Zobacz także CustomDebugStringConvertible, których możesz użyć, aby uzyskać bardziej szczegółowe dane wyjściowe podczas debugowania.


Uwaga dotycząca użytkowania

Możesz zainicjować Stringdowolny typ bez implementowania tego protokołu. Na przykład:

wprowadź opis obrazu tutaj

Z tego powodu doktorzy mówią:

Dlatego odradza się używanie CustomStringConvertiblejako ograniczenia ogólnego lub bezpośredniego dostępu do zgodnego typu description.

Aaron Brager
źródło
37

Odpowiednie dokumenty Apple Swift

Apple podaje następujący przykład:

struct MyType: Printable {
    var name = "Untitled"
    var description: String {
        return "MyType: \(name)"
    }
}

let value = MyType()
println("Created a \(value)")
// prints "Created a MyType: Untitled"

Jeśli spróbujesz tego na placu zabaw, pojawi się ten sam problem, który otrzymujesz ( V11lldb_expr...). Na placu zabaw opis po prawej stronie pojawia się, gdy wywołujesz inicjator, ale printlnnie zwraca on czegoś czytelnego.

Jednak poza placem zabaw ten kod zachowuje się zgodnie z oczekiwaniami. Zarówno twój kod, jak i przykładowy kod z Apple powyżej wypisują poprawne, descriptiongdy są używane w kontekście innym niż plac zabaw.

Myślę, że nie można zmienić tego zachowania na placu zabaw. Może to być po prostu błąd.

EDYCJA : Jestem prawie pewien, że to błąd; Wysłałem raport o błędzie do Apple.

AKTUALIZACJA : W Swift 2 zamiast Printableużywać CustomStringConvertible( odpowiedni link do dokumentu ).

struct MyType: CustomStringConvertible {
    var name = "Untitled"
    var description: String {
        return "MyType: \(name)"
    }
}

let value = MyType()
println("Created a \(value)")
// prints "Created a MyType: Untitled"
Cezary Wójcik
źródło
2

Wygląda na to, że jest to błąd na placu zabaw. Jeśli faktycznie skompilujesz i uruchomisz program normalnie, wypisze:

(10, 20)
(10, 20)
(10, 20)
(10, 20)

zgodnie z oczekiwaniami.

Powinieneś to zgłosić pod adresem https://bugreport.apple.com

Nicholas H.
źródło
1

Alternatywnie w Swift 5+ możesz rozszerzyć String.StringInterpolation

struct Point {
    var x : Int
    var y : Int
}

extension String.StringInterpolation {
    mutating func appendInterpolation(_ value: Point) {
        appendInterpolation("\(value.x):\(value.y)")
    }
}

Spowoduje to zmianę wartości dla, print("\(p)") ale nie dla print(p)- co nadal będzie używać opisu

Ryan Heitner
źródło
0

Jeśli otworzysz widok konsoli: View -> Assistant Editor -> Show Assistant Editor, zobaczysz oczekiwane wydrukowane linie Sprawdzone w xCode 6.3.2 z Yosimite 10.10

wprowadź opis obrazu tutaj

Nikita Kurtin
źródło
0

AppCodezapewnia a Generate| debugDescriptioni `` Generuj | opis ". Lepiej niż wpisywanie ich w strukturze z wieloma członkami.

wprowadź opis obrazu tutaj

StephenBoesch
źródło