Быстрая условная интерполяция строк - PullRequest
0 голосов
/ 30 мая 2019

Я часто ловлю себя на том, что пишу такой код, когда мне нужно построить строку в зависимости от некоторого условия (в данном случае isFavorite):

let me = Contact(name: "Stefan", isFavorite: true)

var message = "Contact \(me.name)"
if me.isFavorite {
    message.append(" is a favorite contact")
}

Это 4 строки или, альтернативно, сложный троичный оператор (еслитогда: еще) для такой простой задачи.У меня всегда плохая совесть с этим ...

Есть ли способ сделать это более элегантно со Swift?

Ответы [ 3 ]

4 голосов
/ 30 мая 2019

Свифт 5

Действительно, есть - я нашел ответ на UIKonf 2019, где я услышал от Эрики Садун, что есть способ, используя Swift 5 String Interpolation, чтобы достичь этого в одной строке. Все, что вам нужно, это многоразовое расширение:

extension String.StringInterpolation {
    mutating func appendInterpolation(if condition: @autoclosure () -> Bool, _ literal: StringLiteralType) {
        guard condition() else { return }
        appendLiteral(literal)
    }
}

Это позволяет вам преобразовать 4 строки в одну:

"Contact: \(me.name)\(if: me.isFavorite, " is a favorite contact")"

Вы можете прочитать о различных возможностях интерполяции строк в Swift в статье Эрики: https://ericasadun.com/2018/12/12/the-beauty-of-swift-5-string-interpolation/

Детская площадка

Начните пачкать руки этим:

import Foundation

// *****************************************************************************
// Many thanks to Erica Sadun for describing the new possibilities of string
// interpolation in Swift 5 ?
// *****************************************************************************


// *****************************************************************************
// Conditional Interpolation

struct Contact {
    let name: String
    let isFavorite: Bool
}
let me = Contact(name: "Stefan", isFavorite: true)

// ***************************************************************** Swift 4

var message = "Contact \(me.name)"
if me.isFavorite {
    message.append(" is favorite")
}
message // we need 4 lines to construct this message!!!
"Contact: \(me.name)\(me.isFavorite ? " is favorite" : "")" // or a complex ternary operator

// ***************************************************************** Swift 5

extension String.StringInterpolation {

    mutating func appendInterpolation(if condition: @autoclosure () -> Bool, _ literal: StringLiteralType) {
        guard condition() else { return }
        appendLiteral(literal)
    }
}
"Contact: \(me.name)\(if: me.isFavorite, " is favorite")" // simple and clean - no extras

// *****************************************************************************
// Optional Interpolation

let optionalMe: Contact? = Contact(name: "Stefan", isFavorite: true)

// ***************************************************************** Swift 4

"Contact: \(optionalMe?.name)" // shows warning

// ***************************************************************** Swift 5

// Interpolate nil value
extension String.StringInterpolation {
    /// Provides `Optional` string interpolation without forcing the
    /// use of `String(describing:)`.
    public mutating func appendInterpolation<T>(_ value: T?, default defaultValue: String) {
        if let value = value {
            appendInterpolation(value)
        } else {
            appendLiteral(defaultValue)
        }
    }
}
let nilContact: Contact? = nil
"Contact: \(nilContact?.name, default: "nil")"

// Strip `Optional`
extension String.StringInterpolation {
    /// Interpolates an optional using "stripped" interpolation, omitting
    /// the word "Optional" from both `.some` and `.none` cases
    public mutating func appendInterpolation<T>(describing value: T?) {
        if let value = value {
            appendInterpolation(value)
        } else {
            appendLiteral("nil")
        }
    }

}
"Contact: \(describing: optionalMe?.name)"
1 голос
/ 30 мая 2019

Можно использовать Тернарный оператор

let msg = "Contact \(me.name)" + (me.isFavorite ? " is a favorite contact" : "")
0 голосов
/ 30 мая 2019

Я склонен создавать вторую переменную String, которая может быть или не быть пустой, и безоговорочно добавлять ее ...

let me = Contact(name: "Stefan", isFavorite: true)
let favorite = me.isFavorite ? " is a favorite contact" : ""

var message = "Contact \(me.name)\(favorite)"
...