一个Swift字符串常量与字符串字面量的类型是否不同?

3
在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,如果有更好的方式处理此类比较检查,请随意提及。)
谢谢!
4个回答

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")
}

2
相关的文档没有提到这个问题(或者我没有找到),但如果你在使用==运算符比较单字符字符串字符时,Swift自动将"!"作为一个Character别名,所以你的“成功案例”可能是因为这个机制起作用了;而这种机制对于bang则不适用,因为它不是一个字面量。但这只是一个猜测,所以我没有在我的答案中包含它。 - Eric Aya
2
我认为你的“猜测”是正确的。 "!" 可以是字符串字面量(默认值),也可以是字符字面量(从上下文推断出来)。let bang = Character("!") 使“失败案例”编译通过。- 因此,这个问题实际上与可选项无关let bang =“!”; if bang == str.characters.last! { } 也不会编译。 - Martin R
1
谢谢!或者,我发现我也可以这样说:let bang =“!”.characters.last - jbbenni
关于该问题与 可选项 无关的观点很好!再次感谢。 - jbbenni

2
正如错误所说,第一个运算符是一个字符串(String),而第二个运算符是一个可选的字符(Character)。
但是你已经展示了如何将字符串转换为字符(Character),所以让我们使用它:
if bang.characters.last == str.characters.last {
    print("Tone it down please")
}

你知道 bang.characters.last 只会返回 "!",但现在它的类型与 str.characters.last 相同,因此比较它们将变得非常简单。

错误实际上并没有说第二个是可选的 Character。它说它是一个可选的 _Element,这不是我认识的东西。但是我明白你的意思,关于从字符串转换为最后一个字符。谢谢。(请参见我在前面答案的评论中发布的变体,以找到另一个定位字符转换的位置。) - jbbenni

1
感谢良好的讨论。这是我自己的答案,通过消除不必要的可选项来改进说明,并展示类型推断的优点和缺点:
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)。
重要提示:常量的类型在声明时就已经确定,而文字的类型是从上下文中推断出来的,因此同一文字在不同的上下文中可能有不同的类型。 文字所具备的灵活类型推断对于常量是不可用的。

-1

不确定这是否完全相关,但我找到了这篇文章,因为我在转换 characters.firstcharacters.lastInt 时遇到了问题。

如果这对任何人有帮助:

let element = characters.first! // the ! is important
let myString = String(element) 
let myInt = Int(myString) // may be nil if character is not an int

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接