感叹号在Swift语言中是什么意思?
具有以下示例:感叹号在Swift语言中是什么意思?,swift,optional,forced-unwrapping,Swift,Optional,Forced Unwrapping,具有以下示例: class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { println("\(name) is being deinitialized") } } class Apartment { let number: Int init(number: Int) { self.numbe
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
var tenant: Person?
deinit { println("Apartment #\(number) is being deinitialized") }
}
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)
然后,当将公寓分配给此人时,他们使用感叹号“展开实例”:
“打开实例”是什么意思?为什么有必要?它与仅执行以下操作有何区别:
john.apartment = number73
var john: Person?
我对斯威夫特语很陌生。只是想把基本的东西记下来
更新:
我遗漏的谜题的一个重要部分(答案中没有直接说明——至少在写这篇文章的时候没有)是当你做以下事情时:
john.apartment = number73
var john: Person?
这并不意味着“
john
属于Person
类型,可能是nil”,正如我最初所想。我只是误解了Person
和Person?
是完全不同的类型。一旦我掌握了,所有其他的?
,代码>疯狂和下面的精彩答案更有意义。john
是可选的var
,它可以包含一个nil
值。要确保该值不是零,请使用代码>在var
名称的末尾
从文件
“一旦确定可选项确实包含值,您可以通过在可选项名称的末尾添加感叹号(!)来访问其基础值。感叹号实际上表示:“我知道此可选项肯定有值;请使用它。”
检查非零值的另一种方法是(可选展开)
John是一个可选的人,这意味着它可以持有一个值或为零
john.apartment = number73
如果john不是可选项,则使用。因为john从不为零,所以我们可以确保它不会以零值调用公寓。而
john!.apartment = number73
向编译器承诺john不是nil,然后展开可选项以获取john的值并访问john的公寓属性。如果知道john不是nil,请使用此选项。如果对nil可选项调用此选项,则会出现运行时错误
文档中包含了一个很好的示例,其中convertedNumber是可选的
if convertedNumber {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
如果john是可选的var(如此声明)
那么约翰就有可能没有价值(用ObjC的说法,零价值)
感叹号基本上告诉编译器“我知道这有一个值,你不需要测试它”。如果你不想使用它,你可以有条件地测试它:
if let otherPerson = john {
otherPerson.apartment = number73
}
只有john有一个值时,才会对其内部进行评估
“打开实例”是什么意思?为什么有必要
据我所知(这对我来说也是非常新鲜的)
术语“包装”意味着我们应该把一个可选变量当作礼物,用闪亮的纸包装,纸可能(很遗憾!)是空的
“包装”时,可选变量的值是一个包含两个可能值(有点像布尔值)的枚举。此枚举描述变量是否包含值(Some(T)
),或不包含值(None
)
如果有值,可以通过“展开”变量(从Some(T)
中获取T
)来获得该值
john!.partment=number73
与john.partment=number73
有何不同
如果您写入可选变量的名称(例如textjohn
,而不包含!
),则这指的是“包装”枚举(Some/None),而不是值本身(T)。因此john
不是Person
的实例,也没有单元成员:
john.apartment
// 'Person?' does not have a member named 'apartment'
实际的Person
值可以通过多种方式展开:
- “强制展开”:
john!
(如果存在,则给出Person
值,如果为零,则给出运行时错误)
- “可选绑定”:
if let p=john{println(p)}
(如果值存在,则执行println
)
- “可选链接”:
john?.learnAboutSwift()
(如果值存在,则执行此组合方法)
我猜您会选择其中一种方法来展开,这取决于nil情况下会发生什么以及可能性有多大。这种语言设计强制显式处理nil情况,我认为这会提高Obj-C的安全性(在Obj-C中很容易忘记处理nil情况)
更新:
感叹号也用于声明“隐式展开选项”的语法中
在到目前为止的示例中,john
变量已声明为var john:Person?
,它是可选的。如果需要该变量的实际值,必须使用上述三种方法之一将其展开
如果它被声明为var john:Person!
,则该变量将是一个隐式展开的可选变量(请参阅苹果书中带有此标题的部分)。在访问该值时无需展开此类变量,john
可以在无需附加语法的情况下使用。但苹果书中说:
当变量可能在以后变为nil时,不应使用隐式展开选项。如果需要在变量的生存期内检查nil值,请始终使用普通可选类型
更新2:
Mike Ash的文章“”为可选类型提供了一些动力。我认为这是一篇很棒、清晰的文章
更新3:
另一篇关于感叹号的隐式展开可选用法的有用文章:“Chris Adamson。这篇文章解释说,这是Apple用于声明Objective-C框架使用的类型(可能包含零)的实用措施。将类型声明为可选(使用?
)或隐式展开(使用!
)是“安全和方便之间的权衡”。在本文给出的示例中,苹果选择将类型声明为i
john.apartment
// 'Person?' does not have a member named 'apartment'
var hw = "Hello World"
//This is an error
if hw
{..}
var nhw : String? = "Hello World"
//This is correct
if nhw
{..}
var john: Person?
john?.apartment = number73
if john != nil {
john.apartment = number73
}
john!.apartment = number73
john.apartment = number73
let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."
let assumedString: String! = "An implicitly unwrapped optional string."
print(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."
var optionalExample: String?
var name:String = "Hello World"
var word:String?
word = name
var cow:String = nil
var dog:String!
dog = cow
Person? thisPerson;
thisPerson.Value
let assumedString: String! = "Some message..."
let implicitString: String = assumedString
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
struct Optional<T> {
var isNil:Boolean
var realObject:T
}
func foo(bar: String!) {
print(bar)
}
func foo(bar: String?) {
print(bar!)
}
enum Optional<T>{
case None
case Some(T)
}
let x: String? = nil //actually means:
let x = Optional<String>.None
let x :String? = "hello" //actually means:
let x = Optional<String>.Some("hello")
var y = x! // actually means:
switch x {
case .Some(let value): y = value
case .None: // Raise an exception
}
let x:String? = something
if let y = x {
// do something with y
}
//Actually means:
switch x{
case .Some(let y): print)(y) // or whatever else you like using
case .None: break
}
enum Optional<Person>{
case .None
case .Some(Person)
}
Simple the Optional variable allows nil to be stored.
var str : String? = nil
str = "Data"
To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"
func get(message : String){
return
}
get(message : str!) // Unwapped to pass as String
if (myNumber != 3){
// if myNumber is NOT 3 do whatever is inside these brackets.
)