Является ли константа Swift String другого типа, чем строковый литерал?

В Swift 2.1 фрагмент ниже генерирует ошибку.

var str = "Hello, playground!"

// Success Case
if "!" == str.characters.last {
    print("Tone it down please")
}

// Fail Case
let bang = "!"

if bang == str.characters.last {  // this line won't compile
    print("Tone it down please")
}

Ошибка компилятора говорит:

Двоичный оператор '==' нельзя применить к операндам типа 'String' и '_Element?'

Итак, каков рекомендуемый способ использования константы, а не литерала в этой ситуации? (Я изучаю Swift, поэтому, пожалуйста, не стесняйтесь упоминать, есть ли способ Swift-er для обработки такого рода сравнительной проверки.)

Спасибо!

4 ответа

Решение

Для вашего "случая провала" это потому, что str.characters.last является необязательным и является Character, но bang это String,

Вы можете безопасно развернуть и сравнить с if let ... whereи использовать String() изменить Character к String для сравнения:

if let last = str.characters.last where String(last) == bang {
    print("Tone it down please")
}

Как говорит ошибка, первый оператор Stringи второй является необязательным Character,

Но вы уже продемонстрировали, что знаете, как превратить строку в Character?так что давайте использовать это:

if bang.characters.last == str.characters.last {
    print("Tone it down please")
}

Ты знаешь что bang.characters.last просто вернусь "!", но теперь он будет того же типа, что и str.characters.lastтак что будет несложно их сравнить.

Спасибо за хорошее обсуждение. Вот мой собственный ответ, чтобы улучшить иллюстрацию путем исключения посторонних опций и продемонстрировать как хорошие, так и плохие выводы типа в игре:

let a:String = "!"              // type is String
let b:Character = "!"           // type is Character
let c = "!".characters.last!    // type is _Element
let bang = "!"                  // inferred type is String

if "!" == a { print("literal matches string") }
if "!" == b { print("literal matches Character") }
if "!" == c { print("literal matches _Element") }

if a == b { print("a matches b") }      // Err: 'String' to 'Character'
if a == c { print("a matches c") }      // Err: 'String' to '_Element' 
if b == c { print("b matches c") }      // OK: 'Character' to '_Element' 

Вывод: литерал, состоящий из одного символа в кавычках, может быть распознан как String или как Character (или эквивалентно _Element), если контекст подсказывает это.

Важно: тип константы постоянно устанавливается при ее объявлении. Тип литерала выводится из его контекста, поэтому один и тот же литерал может иметь разные типы в разных контекстах.

Гибкий вывод типа, предоставленный литералу, не доступен с константой.

Не уверен, что это полностью связано, но я нашел этот пост, так как у меня были проблемы с конвертацией между characters.first, characters.last а также Int,

На случай, если это кому-нибудь поможет:

let element = characters.first! // the ! is important
let myString = String(element) 
let myInt = Int(myString) // may be nil if character is not an int
Другие вопросы по тегам