关于Swift中的变量类型

时间:2016-04-03 20:08:00

标签: swift swift2 swift2.2

我理解String!类型和String?类型之间的区别。但是String类型呢?它与swift中的String!String?有何不同? String!的类型是否与String类型相同?

说,我有一个这样的课:

class Person {
  private var _name: String!

  var name: String {
      return _name
  }

  init(name: String) {
     _name = name
  }
}

没有编译器错误,看起来String类型与String!类型相同。但我不确定......

5 个答案:

答案 0 :(得分:4)

StringString!不相同。恰好在语言中有足够的糖来转换它们。同样,语言中的糖也可以在StringString?之间进行转换(但不能反过来)。

从基础开始。有String。除非有一些强有力的理由,否则当你指的是一串字符时,你应该使用String。其他一切都是"更多东西"除非你需要,否则你不应该添加它。

Optional<String>。这只是一个包含两种情况的枚举,一种是值,另一种是没有值:

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
    case None
    case Some(Wrapped)
    // ...
}

!有一个后缀运算符Optional,如果可用,将返回Wrapped,如果不可用,则会返回崩溃。到目前为止,没有魔力。这是你可以自己建立的东西。

Optional周围有很少的魔法。首先,编译器将类型Wrapped?神奇地转换为Optional<Wrapped>(对于任何Wrapped)。这只是语法糖。这两个符号是相同的。其次,使用?.&#34;运算符&#34;进行可选链接。 (它不是真正的操作员;它是语言的一部分,你自己无法构建它)。然后是可选的促销活动。如果需要,任何类型Wrapped都可以自动和隐式转换为Wrapped?Optional if-let语法之类的其他神奇内容很少,nil Optional.NoneOptional的同义词(我相信他们&#39;}实际上相同)。但是ImplicitlyUnwrappedOptional<Wrapped>实际上只是一个通用类型,实现为枚举。它只是编译器知道特殊事物的类型。

然后有public enum ImplicitlyUnwrappedOptional<Wrapped> : _Reflectable, NilLiteralConvertible { case None case Some(Wrapped) // ... } 。这也只是一个枚举(在Swift 2.2中;这将在Swift 3中改变)。

Optional

这与Wrapped不同,与Wrapped!不同。它是一种完全不同的类型。但它也有一些与之相关的魔力。首先,类型ImplicitlyUnwrappedOptional<Wrapped>IUO<Wrapped>的语法糖。再一次,它只是糖。两者是相同的(在Swift 2.2中,而不是在Swift 3中)。接下来,如果在预期Wrapped的地方找到Wrapped,则会自动转换为Wrapped?,如果没有值,则会崩溃。如果在预期Wrapped?的地方找到它,它将自动转换为String。这些都是神奇的,这就是为什么有时String!if-let 看起来是同一类型的原因。这只是编译器的神奇之处&#34;使它工作&#34;为您添加一个不可见的转换步骤。这并不代表他们真的是同一类型。

IUO主要用于桥接某些Objective-C模式,特别是涉及故事板,并且应该避免在这些情况之外。即使在那些情况下,IUO也只是为了方便起见。您可以使用常规Optionals执行所有相同的操作,您只需更频繁地使用init进行检查。使用Optionals比使用IUO更安全。它很容易思考&#34;我确信这个值在使用之前总会被设置。&#34;就在这个星期,由于对此的错误,我追赶了一个破坏者。 &#34;它应该是&#34;之间的区别。并且&#34;它必须是。&#34;但是,在故事板中使用Optionals完全安全可能非常不方便并且可能会掩盖一些错误(通过什么都不做而不是崩溃),因此这是IUO最常见的地方。

IUO属性曾经对处理可用的self方法很有价值。这在Swift 2.2中不再是问题,因此使用已经消失。最后一个纯粹的Swift&#34;我遇到的用途是当你必须将self传递给你存储为属性的东西的初始化时(那时你不能通过func f() { let x: String? = nil guard let y: String = x else { print("failed") return } } func g() { let x: String? = nil guard let y: String! = x else { print("failed") return } print(y.dynamicType, y) } f() # failed g() # Optional<String> nil ,因为你的所有属性都已初始化)。这是一个不幸的用例而且非常混乱,我希望我们能够解决这个问题。在这些情况之外,你应该避免使用Implicitly Unwrapped Optionals。

答案 1 :(得分:1)

StringString!同时相同且不同。如果将let或var声明为String,则必须在init方法中设置一些值。如果您将其声明为String!,则可以在需要时设置值,但必须在读取此值之前进行设置。

因此,如果您的_namenil,您的应用就会崩溃。

如果将其声明为String,编译器会在第一次读取之前保证_name != nil。如果您将其声明为String!,则应该保证。

由于这个原因,这件事的类型相同:

var test1: String = "test"
var test2: String! = "test"

if test1 is String { // True
    print("test1 is String")
}
if test2 is String { // True
    print("test2 is String")
}

这种类型是相同的,但这是不同的

答案 2 :(得分:1)

注意这两个功能之间的区别:

var v = [1,2,3,4,5]
v.map(function(a) {return a+1}) === v.map(function(a) { return a+1;}) 

答案 3 :(得分:0)

您最好阅读swift documentation,而不是此处的任何答案。正确地看待swift的类型系统是非常重要的,所以首先要这样做。

答案 4 :(得分:-1)

String!String?都是可选类型。

使用String?要求您测试值是 nil (。Noone)还是值(.Some)。例如,使用guard语句或if-let子句。

String!是一个可选项,假定为非零并自动解包。这使您可以编写更清晰的代码,并避免在使用值的任何地方展开。但是:如果您的值 nil ,则会发生致命错误。