2

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

说,我有这样的课:

class Person {
  private var _name: String!

  var name: String {
      return _name
  }

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

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

4

5 回答 5

4

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

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

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

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

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

周围有几件魔法Optional。首先,类型被编译器Wrapped?神奇地转换为(对于 any )。这只是语法糖。这两个符号是相同的。其次,存在与“操作符”的可选链接(它不是真正的操作符;它是语言的一部分,您无法自己构建它)。然后是可选的促销。如果需要,任何类型都可以自动隐式转换为。像语法这样的魔法很少有其他的东西,并且有一个同义词(我相信它们实际上是相同的)。但实际上只是一个泛型类型,实现为枚举。它'Optional<Wrapped>Wrapped?.WrappedWrapped?Optionalif-letnilOptional.NoneOptional

然后有ImplicitlyUnwrappedOptional<Wrapped>。这也只是一个枚举(在 Swift 2.2 中;这将在 Swift 3 中改变)。

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

这不一样,Optional也不一样Wrapped。这是一个完全不同的类型。但它也有一些与之相关的魔法。首先,类型Wrapped!ImplicitlyUnwrappedOptional<Wrapped>. 再说一次,这只是糖。两者是相同的(在 Swift 2.2 中,而不是在 Swift 3 中)。接下来,如果IUO<Wrapped>在预期的地方找到,如果没有值Wrapped,它会自动转换为或崩溃。Wrapped如果在Wrapped?预期的地方找到它,它将自动转换为Wrapped?. 这些很神奇,这就是为什么有时String看起来String! 同一类型的原因。这只是编译器通过添加一个不可见的转换步骤神奇地为您“使其工作”。这并不意味着它们真的是同一类型。

IUO 在桥接某些 Objective-C 模式时最有用,尤其是涉及 Storyboard,在这些情况之外应避免使用。即使在这些情况下,IUO 也只是为了方便。您可以使用常规 Optionals 做所有相同的事情,您只需要if-let更频繁地检查它们。使用 Optionals 比使用 IUO 安全得多。很容易想到“我确定这个值总是在使用之前就设置好了”。就在本周,我追赶了一个撞车者,因为这件事是错误的。“它应该是”和“它必须是”之间是有区别的。但是,在 Storyboard 中使用 Optionals 完全安全可能会非常不方便,并且可能会掩盖一些错误(通过什么都不做而不是崩溃),所以这是 IUO 最常见的地方。

IUO 属性曾经对处理失败的init方法很有价值。这在 Swift 2.2 中不再是一个问题,所以这种使用已经消失了。我遇到的最后一个“纯 Swift”使用是当您必须将self存储为属性的内容传递给初始化程序时(此时您不能通过self,因为您的所有属性都已初始化)。这是一个不幸的用例,非常混乱,我希望我们能找到解决办法。在这些情况之外,您应该避免隐式展开的选项。

于 2016-04-04T00:02:22.937 回答
1

请注意这两个函数之间的区别:

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
于 2016-04-04T00:02:27.577 回答
1

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

因此,如果您_name愿意nil,您的应用程序将崩溃。

如果将其声明为,编译器会在第一次阅读之前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")
}

这种类型是平等的,但这种东西是不同的

于 2016-04-03T20:17:44.680 回答
0

您最好阅读swift 文档而不是此处的任何答案。正确理解 swift 的类型系统非常重要,所以先做。

于 2016-04-03T22:11:42.827 回答
-1

两者String!String?都是可选类型。

使用String?要求您测试该值是nil (.None) 还是值 (.Some)。例如使用保护语句或 if-let 子句。

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

于 2016-04-03T22:21:20.303 回答