Optional 学习
https://github.com/apple/swift/blob/master/stdlib/public/core/Optional.swift
涉及到东西
范型
枚举
ExpressibleByNilLiteral
CustomReflectable
Equatable
Hashable
_ObjectiveCBridgeable
范型
整个数据类型是
enum:ExpressibleByNilLiteral
case none
case some(Wrapped)
构造方法
@_transparent
publicinit(_some: Wrapped) {self=.some(some) }
@_transparent
publicinit(nilLiteral: ()) {
self=.none
}
对象方法
@inlinable
publicfuncmap(
_transform: (Wrapped)throws->U
)rethrows->U?{
switchself{
case.some(lety):
return.some(trytransform(y))
case.none:
return.none
}
}
@inlinable
publicfuncflatMap(
_transform: (Wrapped)throws->U?
)rethrows->U?{
switchself{
case.some(lety):
returntrytransform(y)
case.none:
return.none
}
}
计算属性
@inlinable
publicvarunsafelyUnwrapped:Wrapped {
@inline(__always)
get{
ifletx=self{
returnx
}
_debugPreconditionFailure("unsafelyUnwrapped of nil optional")
}
}
@inlinable
internalvar_unsafelyUnwrappedUnchecked:Wrapped {
@inline(__always)
get{
ifletx=self{
return x
}
_internalInvariantFailure("_unsafelyUnwrappedUnchecked of nil optional")
}
}
}
//===----------------------------------------------------------------------===//
//
//This source file is part of the Swift.org open source project
//
//Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
//Licensed under Apache License v2.0 with Runtime Library Exception
//
//See https://swift.org/LICENSE.txt for license information
//See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///A type that represents either a wrapped value or `nil`, the absence of a
///value.
///
///You use the `Optional` type whenever you use optional values, even if you
///never type the word `Optional`. Swift's type system usually shows the
///wrapped type's name with a trailing question mark (`?`) instead of showing
///the full type name. For example, if a variable has the type `Int?`, that's
///just another way of writing `Optional`. The shortened form is
///preferred for ease of reading and writing code.
///
///The types of `shortForm` and `longForm` in the following code sample are
///the same:
///
///let shortForm: Int? = Int("42")
///let longForm: Optional = Int("42")
///
///The `Optional` type is an enumeration with two cases. `Optional.none` is
///equivalent to the `nil` literal. `Optional.some(Wrapped)` stores a wrapped
///value. For example:
///
///let number: Int? = Optional.some(42)
///let noNumber: Int? = Optional.none
///print(noNumber == nil)
///// Prints "true"
///
///You must unwrap the value of an `Optional` instance before you can use it
///in many contexts. Because Swift provides several ways to safely unwrap
///optional values, you can choose the one that helps you write clear,
///concise code.
///
///The following examples use this dictionary of image names and file paths:
///
///let imagePaths = ["star": "/glyphs/star.png",
///"portrait": "/images/content/portrait.jpg",
///"spacer": "/images/shared/spacer.gif"]
///
///Getting a dictionary's value using a key returns an optional value, so
///`imagePaths["star"]` has type `Optional` or, written in the
///preferred manner, `String?`.
///
///Optional Binding
///----------------
///
///To conditionally bind the wrapped value of an `Optional` instance to a new
///variable, use one of the optional binding control structures, including
///`if let`, `guard let`, and `switch`.
///
///if let starPath = imagePaths["star"] {
///print("The star image is at '\(starPath)'")
///} else {
///print("Couldn't find the star image")
///}
///// Prints "The star image is at '/glyphs/star.png'"
///
///Optional Chaining
///-----------------
///
///To safely access the properties and methods of a wrapped instance, use the
///postfix optional chaining operator (postfix `?`). The following example uses
///optional chaining to access the `hasSuffix(_:)` method on a `String?`
///instance.
///
///if imagePaths["star"]?.hasSuffix(".png") == true {
///print("The star image is in PNG format")
///}
///// Prints "The star image is in PNG format"
///
///Using the Nil-Coalescing Operator
///---------------------------------
///
///Use the nil-coalescing operator (`??`) to supply a default value in case
///the `Optional` instance is `nil`. Here a default path is supplied for an
///image that is missing from `imagePaths`.
///
///let defaultImagePath = "/images/default.png"
///let heartPath = imagePaths["heart"] ?? defaultImagePath
///print(heartPath)
///// Prints "/images/default.png"
///
///The `??` operator also works with another `Optional` instance on the
///right-hand side. As a result, you can chain multiple `??` operators
///together.
///
///let shapePath = imagePaths["cir"] ?? imagePaths["squ"] ?? defaultImagePath
///print(shapePath)
///// Prints "/images/default.png"
///
///Unconditional Unwrapping
///------------------------
///
///When you're certain that an instance of `Optional` contains a value, you
///can unconditionally unwrap the value by using the forced
///unwrap operator (postfix `!`). For example, the result of the failable `Int`
///initializer is unconditionally unwrapped in the example below.
///
///let number = Int("42")!
///print(number)
///// Prints "42"
///
///You can also perform unconditional optional chaining by using the postfix
///`!` operator.
///
///let isPNG = imagePaths["star"]!.hasSuffix(".png")
///print(isPNG)
///// Prints "true"
///
///Unconditionally unwrapping a `nil` instance with `!` triggers a runtime
///error.
@frozen
publicenumOptional:ExpressibleByNilLiteral{
//The compiler has special knowledge of Optional, including the fact
//that it is an `enum` with cases named `none` and `some`.
///The absence of a value.
///
///In code, the absence of a value is typically written using the `nil`
///literal rather than the explicit `.none` enumeration case.
casenone
///The presence of a value, stored as `Wrapped`.
casesome(Wrapped)
///Creates an instance that stores the given value.
@_transparent
publicinit(_some: Wrapped) {self=.some(some) }
///Evaluates the given closure when this `Optional` instance is not `nil`,
///passing the unwrapped value as a parameter.
///
///Use the `map` method with a closure that returns a non-optional value.
///This example performs an arithmetic operation on an
///optional integer.
///
///let possibleNumber: Int? = Int("42")
///let possibleSquare = possibleNumber.map { $0 * $0 }
///print(possibleSquare)
///// Prints "Optional(1764)"
///
///let noNumber: Int? = nil
///let noSquare = noNumber.map { $0 * $0 }
///print(noSquare)
///// Prints "nil"
///
///- Parameter transform: A closure that takes the unwrapped value
///of the instance.
///- Returns: The result of the given closure. If this instance is `nil`,
///returns `nil`.
@inlinable
publicfuncmap(
_transform: (Wrapped)throws->U
)rethrows->U?{
switchself{
case.some(lety):
return.some(trytransform(y))
case.none:
return.none
}
}
///Evaluates the given closure when this `Optional` instance is not `nil`,
///passing the unwrapped value as a parameter.
///
///Use the `flatMap` method with a closure that returns an optional value.
///This example performs an arithmetic operation with an optional result on
///an optional integer.
///
///let possibleNumber: Int? = Int("42")
///let nonOverflowingSquare = possibleNumber.flatMap { x -> Int? in
///let (result, overflowed) = x.multipliedReportingOverflow(by: x)
///return overflowed ? nil : result
///}
///print(nonOverflowingSquare)
///// Prints "Optional(1764)"
///
///- Parameter transform: A closure that takes the unwrapped value
///of the instance.
///- Returns: The result of the given closure. If this instance is `nil`,
///returns `nil`.
@inlinable
publicfuncflatMap(
_transform: (Wrapped)throws->U?
)rethrows->U?{
switchself{
case.some(lety):
returntrytransform(y)
case.none:
return.none
}
}
extensionOptional:CustomDebugStringConvertible{
///A textual representation of this instance, suitable for debugging.
publicvardebugDescription:String{
switchself{
case.some(letvalue):
varresult="Optional("
debugPrint(value,terminator:"",to:&result)
result+=")"
returnresult
case.none:
return"nil"
}
}
}
extensionOptional:CustomReflectable{
publicvarcustomMirror:Mirror{
switchself{
case.some(letvalue):
returnMirror(
self,
children: ["some":value ],
displayStyle: .optional)
case.none:
returnMirror(self,children: [:],displayStyle: .optional)
}
}
}
@_transparent
public//COMPILER_INTRINSIC
func_diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
_filenameLength: Builtin.Word,
_filenameIsASCII: Builtin.Int1,
_line: Builtin.Word,
_isImplicitUnwrap: Builtin.Int1) {
//Cannot use _preconditionFailure as the file and line info would not be
//printed.
ifBool(_isImplicitUnwrap) {
_preconditionFailure(
"Unexpectedly found nil while implicitly unwrapping an Optional value",
file:StaticString(_start: _filenameStart,
utf8CodeUnitCount: _filenameLength,
isASCII: _filenameIsASCII),
line:UInt(_line))
}else{
_preconditionFailure(
"Unexpectedly found nil while unwrapping an Optional value",
file:StaticString(_start: _filenameStart,
utf8CodeUnitCount: _filenameLength,
isASCII: _filenameIsASCII),
line:UInt(_line))
}
}
extensionOptional:EquatablewhereWrapped:Equatable{
///Returns a Boolean value indicating whether two optional instances are
///equal.
///
///Use this equal-to operator (`==`) to compare any two optional instances of
///a type that conforms to the `Equatable` protocol. The comparison returns
///`true` if both arguments are `nil` or if the two arguments wrap values
///that are equal. Conversely, the comparison returns `false` if only one of
///the arguments is `nil` or if the two arguments wrap values that are not
///equal.
///
///let group1 = [1, 2, 3, 4, 5]
///let group2 = [1, 3, 5, 7, 9]
///if group1.first == group2.first {
///print("The two groups start the same.")
///}
///// Prints "The two groups start the same."
///
///You can also use this operator to compare a non-optional value to an
///optional that wraps the same type. The non-optional value is wrapped as an
///optional before the comparison is made. In the following example, the
///`numberToMatch` constant is wrapped as an optional before comparing to the
///optional `numberFromString`:
///
///let numberToFind: Int = 23
///let numberFromString: Int? = Int("23") // Optional(23)
///if numberToFind == numberFromString {
///print("It's a match!")
///}
///// Prints "It's a match!"
///
///An instance that is expressed as a literal can also be used with this
///operator. In the next example, an integer literal is compared with the
///optional integer `numberFromString`. The literal `23` is inferred as an
///`Int` instance and then wrapped as an optional before the comparison is
///performed.
///
///if 23 == numberFromString {
///print("It's a match!")
///}
///// Prints "It's a match!"
///
///- Parameters:
///- lhs: An optional value to compare.
///- rhs: Another optional value to compare.
@inlinable
publicstaticfunc==(lhs: Wrapped?,rhs: Wrapped?)->Bool{
switch(lhs, rhs) {
caselet(l?, r?):
returnl==r
case(nil,nil):
returntrue
default:
returnfalse
}
}
}
extensionOptional:HashablewhereWrapped:Hashable{
///Hashes the essential components of this value by feeding them into the
///given hasher.
///
///- Parameter hasher: The hasher to use when combining the components
///of this instance.
@inlinable
publicfunchash(intohasher:inoutHasher) {
switchself{
case.none:
hasher.combine(0asUInt8)
case.some(letwrapped):
hasher.combine(1asUInt8)
hasher.combine(wrapped)
}
}
}
//Enable pattern matching against the nil literal, even if the element type
//isn't equatable.
@frozen
publicstruct_OptionalNilComparisonType:ExpressibleByNilLiteral{
///Create an instance initialized with `nil`.
@_transparent
publicinit(nilLiteral: ()) {
}
}
extensionOptional{
///Returns a Boolean value indicating whether an argument matches `nil`.
///
///You can use the pattern-matching operator (`~=`) to test whether an
///optional instance is `nil` even when the wrapped value's type does not
///conform to the `Equatable` protocol. The pattern-matching operator is used
///internally in `case` statements for pattern matching.
///
///The following example declares the `stream` variable as an optional
///instance of a hypothetical `DataStream` type, and then uses a `switch`
///statement to determine whether the stream is `nil` or has a configured
///value. When evaluating the `nil` case of the `switch` statement, this
///operator is called behind the scenes.
///
///var stream: DataStream? = nil
///switch stream {
///case nil:
///print("No data stream is configured.")
///case let x?:
///print("The data stream has \(x.availableBytes) bytes available.")
///}
///// Prints "No data stream is configured."
///
///- Note: To test whether an instance is `nil` in an `if` statement, use the
///equal-to operator (`==`) instead of the pattern-matching operator. The
///pattern-matching operator is primarily intended to enable `case`
///statement pattern matching.
///
///- Parameters:
///- lhs: A `nil` literal.
///- rhs: A value to match against `nil`.
@_transparent
publicstaticfunc~=(lhs: _OptionalNilComparisonType,rhs: Wrapped?)->Bool{
switchrhs {
case.some:
returnfalse
case.none:
returntrue
}
}
//Enable equality comparisons against the nil literal, even if the
//element type isn't equatable
///Returns a Boolean value indicating whether the left-hand-side argument is
///`nil`.
///
///You can use this equal-to operator (`==`) to test whether an optional
///instance is `nil` even when the wrapped value's type does not conform to
///the `Equatable` protocol.
///
///The following example declares the `stream` variable as an optional
///instance of a hypothetical `DataStream` type. Although `DataStream` is not
///an `Equatable` type, this operator allows checking whether `stream` is
///`nil`.
///
///var stream: DataStream? = nil
///if stream == nil {
///print("No data stream is configured.")
///}
///// Prints "No data stream is configured."
///
///- Parameters:
///- lhs: A value to compare to `nil`.
///- rhs: A `nil` literal.
@_transparent
publicstaticfunc==(lhs: Wrapped?,rhs: _OptionalNilComparisonType)->Bool{
switchlhs {
case.some:
returnfalse
case.none:
returntrue
}
}
///Returns a Boolean value indicating whether the left-hand-side argument is
///not `nil`.
///
///You can use this not-equal-to operator (`!=`) to test whether an optional
///instance is not `nil` even when the wrapped value's type does not conform
///to the `Equatable` protocol.
///
///The following example declares the `stream` variable as an optional
///instance of a hypothetical `DataStream` type. Although `DataStream` is not
///an `Equatable` type, this operator allows checking whether `stream` wraps
///a value and is therefore not `nil`.
///
///var stream: DataStream? = fetchDataStream()
///if stream != nil {
///print("The data stream has been configured.")
///}
///// Prints "The data stream has been configured."
///
///- Parameters:
///- lhs: A value to compare to `nil`.
///- rhs: A `nil` literal.
@_transparent
publicstaticfunc!=(lhs: Wrapped?,rhs: _OptionalNilComparisonType)->Bool{
switchlhs {
case.some:
returntrue
case.none:
returnfalse
}
}
///Returns a Boolean value indicating whether the right-hand-side argument is
///`nil`.
///
///You can use this equal-to operator (`==`) to test whether an optional
///instance is `nil` even when the wrapped value's type does not conform to
///the `Equatable` protocol.
///
///The following example declares the `stream` variable as an optional
///instance of a hypothetical `DataStream` type. Although `DataStream` is not
///an `Equatable` type, this operator allows checking whether `stream` is
///`nil`.
///
///var stream: DataStream? = nil
///if nil == stream {
///print("No data stream is configured.")
///}
///// Prints "No data stream is configured."
///
///- Parameters:
///- lhs: A `nil` literal.
///- rhs: A value to compare to `nil`.
@_transparent
publicstaticfunc==(lhs: _OptionalNilComparisonType,rhs: Wrapped?)->Bool{
switchrhs {
case.some:
returnfalse
case.none:
returntrue
}
}
///Returns a Boolean value indicating whether the right-hand-side argument is
///not `nil`.
///
///You can use this not-equal-to operator (`!=`) to test whether an optional
///instance is not `nil` even when the wrapped value's type does not conform
///to the `Equatable` protocol.
///
///The following example declares the `stream` variable as an optional
///instance of a hypothetical `DataStream` type. Although `DataStream` is not
///an `Equatable` type, this operator allows checking whether `stream` wraps
///a value and is therefore not `nil`.
///
///var stream: DataStream? = fetchDataStream()
///if nil != stream {
///print("The data stream has been configured.")
///}
///// Prints "The data stream has been configured."
///
///- Parameters:
///- lhs: A `nil` literal.
///- rhs: A value to compare to `nil`.
@_transparent
publicstaticfunc!=(lhs: _OptionalNilComparisonType,rhs: Wrapped?)->Bool{
switchrhs {
case.some:
returntrue
case.none:
returnfalse
}
}
}
///Performs a nil-coalescing operation, returning the wrapped value of an
///`Optional` instance or a default value.
///
///A nil-coalescing operation unwraps the left-hand side if it has a value, or
///it returns the right-hand side as a default. The result of this operation
///will have the non-optional type of the left-hand side's `Wrapped` type.
///
///This operator uses short-circuit evaluation: `optional` is checked first,
///and `defaultValue` is evaluated only if `optional` is `nil`. For example:
///
///func getDefault() -> Int {
///print("Calculating default...")
///return 42
///}
///
///let goodNumber = Int("100") ?? getDefault()
///// goodNumber == 100
///
///let notSoGoodNumber = Int("invalid-input") ?? getDefault()
///// Prints "Calculating default..."
///// notSoGoodNumber == 42
///In this example, `goodNumber` is assigned a value of `100` because
///`Int("100")` succeeded in returning a non-`nil` result. When
///`notSoGoodNumber` is initialized, `Int("invalid-input")` fails and returns
///`nil`, and so the `getDefault()` method is called to supply a default
///value.
///- Parameters:
///- optional: An optional value.
///- defaultValue: A value to use as a default. `defaultValue` is the same
///type as the `Wrapped` type of `optional`.
@_transparent
publicfunc??(optional: T?,defaultValue:@autoclosure()throws->T)
rethrows->T {
switchoptional{
case.some(letvalue):
returnvalue
case.none:
returntrydefaultValue()
}
}
///Performs a nil-coalescing operation, returning the wrapped value of an
///`Optional` instance or a default `Optional` value.
///
///A nil-coalescing operation unwraps the left-hand side if it has a value, or
///returns the right-hand side as a default. The result of this operation
///will be the same type as its arguments.
///
///This operator uses short-circuit evaluation: `optional` is checked first,
///and `defaultValue` is evaluated only if `optional` is `nil`. For example:
///
///let goodNumber = Int("100") ?? Int("42")
///print(goodNumber)
///// Prints "Optional(100)"
///
///let notSoGoodNumber = Int("invalid-input") ?? Int("42")
///print(notSoGoodNumber)
///// Prints "Optional(42)"
///
///In this example, `goodNumber` is assigned a value of `100` because
///`Int("100")` succeeds in returning a non-`nil` result. When
///`notSoGoodNumber` is initialized, `Int("invalid-input")` fails and returns
///`nil`, and so `Int("42")` is called to supply a default value.
///
///Because the result of this nil-coalescing operation is itself an optional
///value, you can chain default values by using `??` multiple times. The
///first optional value that isn't `nil` stops the chain and becomes the
///result of the whole expression. The next example tries to find the correct
///text for a greeting in two separate dictionaries before falling back to a
///static default.
///
///let greeting = userPrefs[greetingKey] ??
///defaults[greetingKey] ?? "Greetings!"
///
///If `userPrefs[greetingKey]` has a value, that value is assigned to
///`greeting`. If not, any value in `defaults[greetingKey]` will succeed, and
///if not that, `greeting` will be set to the non-optional default value,
///`"Greetings!"`.
///
///- Parameters:
///- optional: An optional value.
///- defaultValue: A value to use as a default. `defaultValue` and
///`optional` have the same type.
@_transparent
publicfunc??(optional: T?,defaultValue:@autoclosure()throws->T?)
rethrows->T?{
switchoptional{
case.some(letvalue):
returnvalue
case.none:
returntrydefaultValue()
}
}
//===----------------------------------------------------------------------===//
//Bridging5
//===----------------------------------------------------------------------===//
#if_runtime(_ObjC)
extensionOptional:_ObjectiveCBridgeable {
//The object that represents `none` for an Optional of this type.
internalstaticvar_nilSentinel:AnyObject{
@_silgen_name("_swift_Foundation_getOptionalNilSentinelObject")
get
}
publicfunc_bridgeToObjectiveC()->AnyObject{
//Bridge a wrapped value by unwrapping.
ifletvalue=self{
return_bridgeAnythingToObjectiveC(value)
}
//Bridge nil using a sentinel.
returntype(of:self)._nilSentinel
}
publicstaticfunc_forceBridgeFromObjectiveC(
_source:AnyObject,
result:inoutOptional?
) {
//Map the nil sentinel back to .none.
//NB that the signature of _forceBridgeFromObjectiveC adds another level
//of optionality, so we need to wrap the immediate result of the conversion
//in `.some`.
ifsource===_nilSentinel {
result=.some(.none)
return
}
//Otherwise, force-bridge the underlying value.
letunwrappedResult=sourceas!Wrapped
result=.some(.some(unwrappedResult))
}
publicstaticfunc_conditionallyBridgeFromObjectiveC(
_source:AnyObject,
result:inoutOptional?
)->Bool{
//Map the nil sentinel back to .none.
//NB that the signature of _forceBridgeFromObjectiveC adds another level
//of optionality, so we need to wrap the immediate result of the conversion
//in `.some` to indicate success of the bridging operation, with a nil
//result.
ifsource===_nilSentinel {
result=.some(.none)
returntrue
}
//Otherwise, try to bridge the underlying value.
ifletunwrappedResult=sourceas?Wrapped {
result=.some(.some(unwrappedResult))
returntrue
}else{
result=.none
returnfalse
}
}
@_effects(readonly)
publicstaticfunc_unconditionallyBridgeFromObjectiveC(_source:AnyObject?)
->Optional
ifletnonnullSource=source {
//Map the nil sentinel back to none.
ifnonnullSource===_nilSentinel {
return.none
}else{
return.some(nonnullSourceas!Wrapped)
}
}else{
//If we unexpectedly got nil, just map it to `none` too.
return.none
}
}
}
#endif