enum Text: Equatable {
case plain(String)
case attributed(NSAttributedString)
}
I've made it conform to ExpressibleByStringLiteral
extension Text: ExpressibleByStringLiteral {
public typealias StringLiteralType = String
public init(stringLiteral value: StringLiteralType) {
self = .plain(value)
}
}
With all this, I can do the following, just like I would expect:
let text: Text = "Hello" // .plain("Hello")
let text2: Text? = "Hello" // .plain("Hello")
But I get compiler errors for the following:
let nilString: String? = nil
let text3: Text? = nilString // Cannot convert value of type 'String?' to expected argument type 'Text?'
func foo(text: Text?) { /** foo **/ }
foo(text: "Hello") // Cannot convert value of type 'String' to expected argument type 'Text?'
func bar(text: Text?) { /** bar **/ }
bar(text: nilString) // Cannot convert value of type 'String?' to expected argument type 'Text?'
How can I get those to work ?
I've also tried to extend Optional: ExpressibleByStringLiteral where Wrapped: ExpressibleByStringLiteral, but that didn't help.
String literals are different from Strings. You could treat things like "Hello" as string literals, which are not bound to a specific type yet. If no other information is provide, the compiler will just assume that it is String.
bar(text: nilString) won't work because you're converting from String to Text?, not string literal to Text.
(Un)fortunately no. Conversion between concrete types (String -> Text) incurs some overhead, and Swift makes sure that you notice them. In this scenario, you usually use an initializer. If Text.StringLiteral is String, you can probably just use:
ExpressibleByStringLiteral is usually for types that you know the value at compile time. If it's a type that just work with dynamic strings, I'd just have a type conversion initializer.