将swift变量包装为可选变量的缩写?
Swift允许我们使用速记符号将swift变量包装为可选变量的缩写?,swift,variables,syntax,casting,optional,Swift,Variables,Syntax,Casting,Optional,Swift允许我们使用速记符号str以展开可选的文件。但是如果我们想做相反的事情呢 假设我有一个变量: var str = String() // String 是否有任何简写符号可将其转换为可选(即字符串?或字符串!) (例如,我想做一些类似于var strOptional=?(str)) 或者,如果没有此符号的简写,我如何将其转换为可选,而不明确提及其类型(例如,我不想提及String) 换句话说,我知道我可以使用以下任何方法将变量包装为可选变量: var strOptional = st
str代码>以展开可选的文件。但是如果我们想做相反的事情呢
假设我有一个变量:
var str = String() // String
是否有任何简写符号可将其转换为可选(即字符串?
或字符串!
)
(例如,我想做一些类似于var strOptional=?(str)
)
或者,如果没有此符号的简写,我如何将其转换为可选,而不明确提及其类型(例如,我不想提及String
)
换句话说,我知道我可以使用以下任何方法将变量包装为可选变量:
var strOptional = str as String?
var strOptional: String? = str
var strOptional = String?(str)
。。。但在每种情况下,我都必须显式地编写String
如果没有速记语法,我宁愿写这样的东西:var strOptional=str作为typeof?(str)
。(优点是,如果变量的类型在代码库中频繁更改,那么更新的地方就会少一个。)
关于这一点的实际示例,假设我想使用AVCaptureDevice,并使用以下代码:
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
device.lockForConfiguration(nil)
lockForConfiguration()
将在没有摄像机的设备上运行时崩溃,并且编译器不会就此向我发出警告。原因是根据文档[1],带有MediaType的DefaultDevice
可能返回nil
,但它被定义为返回AVCaptureDevice代码>
要修复这样的错误API,最好执行以下操作:
let device = ?(AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo))
。。。获取AVCaptureDevice?
,并让编译器捕获我可能犯的任何错误
目前,我必须求助于更详细的:
let device: AVCaptureDevice? = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
另一个例子:
prefix operator ??? {}
prefix func ??? <T> (x: T) -> T? {
return Optional(x)
}
在本例中,我希望为变量指定一个默认值,即字符串,但稍后,我可能希望为其指定一个nil
值
var myString = "Hi"
// ...
if (someCondition()) {
myString = nil // Syntax error: myString is String
}
目前我不得不求助于var myString:String?=“Hi”
但是像var myString=?(“Hi”)
这样的东西就不会那么冗长了
[1] 如果打开AVCaptureDevice.h,您将看到有关返回值的以下文档:“具有给定媒体类型的默认设备,如果不存在具有该媒体类型的设备,则为nil。”要包装变量,可以使用运算符重载和通用函数。例如:
prefix operator ??? {}
prefix func ??? <T> (x: T) -> T? {
return Optional(x)
}
据我所知,这个问题是以轻松的精神提出的,您可以定义一个后缀运算符,它使用的字符比理想解少一个字符(一对paren和一个问号):
也许狡猾运算符的一个更有趣的用法是更高阶的运算符函数,它将T->U
s提升到T?->U?
s
func opt <T, U> (f: T -> U) -> T? -> U? { // we'll implement this as an operator
return { $0.map(f) }
}
postfix operator ->? {}
postfix func ->? <T, U> (f: T -> U) -> T? -> U? {
return { $0.map(f) }
}
这相当于:
opt(square)(i)
debugPrintln(op.map(square))
这相当于(但可能比):
与“管道前进”操作符一起使用时,所有这些都更有意义:
infix operator |> { associativity left precedence 89 }
func |> <A, B>(a: A, f: A -> B) -> B {
return f(a)
}
或
或者我们可以将它们合并到一个可选的管道转发中,它也可以处理隐式展开的选项:
infix operator ?> { associativity left precedence 89 }
func ?> <T, U> (lhs: T?, rhs: T -> U) -> U? {
return lhs.map(rhs)
}
let im: Int! = 5
let op: Int? = 5
im ?> square |> debugPrintln //--> Optional(25)
op ?> square |> debugPrintln //--> Optional(25)
可选只是swift中的一个枚举,因此您可以执行:Optional(str)
从swift界面:
/// A type that can represent either a `Wrapped` value or `nil`, the absence
/// of a value.
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
/// Construct a `nil` instance.
public init()
/// Construct a non-`nil` instance that stores `some`.
public init(_ some: Wrapped)
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
@warn_unused_result
public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
/// Returns `nil` if `self` is `nil`, `f(self!)` otherwise.
@warn_unused_result
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}
///一种类型,可以表示'Wrapped'值或'nil',即不存在
///有价值的。
公共枚举可选:_可反射,NilLiteralConvertible{
无案例
包装箱(已包装)
///构造一个'nil'实例。
公共init()
///构造一个存储“some”的非“nil”实例。
public init(usome:Wrapped)
///如果`self==nil`,则返回`nil`。否则,返回`f(self!)`。
@警告未使用的结果
公共func地图(@noescape f:(包装)投掷->U)再次投掷->U?
///如果'self'为'nil',则返回'nil',否则返回'f(self!)'。
@警告未使用的结果
公共func平面图(@noescape f:(包装)投掷->U?)再投掷->U?
///创建一个用“nil”初始化的实例。
公共init(nilLiteral:())
}
Hmm,我删除了我的答案。你有足够的代表性仍然可以看到它。我的大部分答案仍然适用,但我认为,AVCaptureDevice
是个顽固分子。当苹果第一次推出Swift时,基本上所有东西都会隐式地返回未包装的可选项,但他们应该将所有这些转换为非可选项或常规可选项。这就是Objective-C nullability宏的作用。@nhgrif:谢谢您的评论。我添加了另一个例子,说明这可能是有用的,它不涉及苹果的框架。在第二个例子中,我认为明确使用您的类型很重要。苹果没有将预处理器宏引入Swift是有原因的……我同意@nhgrif的观点。AVFoundation只是还没有移植。后者很明显是让myString=Optional(“Hi”)
(但这不适用于!
类型)。如果有人提出一些简单的语法,我不会反对,但我肯定不会创建运算符或任何类似的重载。你可以很容易地将它封装在一个名为lift
的函数中,该函数接受可选或非可选,并返回可选。我正在研究完全相同的答案。这并不能解决函数返回显式展开的可选项(您希望将其视为常规可选项)的问题。例如,如果func test()->Int!{return 17}
被这样调用,让a=??test()
,那么a
将具有类型Int
而不是Int?
。“?”不是一个糟糕的运算符选择,因为这是nil合并运算符的符号吗?
infix operator |> { associativity left precedence 89 }
func |> <A, B>(a: A, f: A -> B) -> B {
return f(a)
}
i |> opt(square)
i |> square->?
infix operator ?> { associativity left precedence 89 }
func ?> <T, U> (lhs: T?, rhs: T -> U) -> U? {
return lhs.map(rhs)
}
let im: Int! = 5
let op: Int? = 5
im ?> square |> debugPrintln //--> Optional(25)
op ?> square |> debugPrintln //--> Optional(25)
debugPrintln(op.map(square))
/// A type that can represent either a `Wrapped` value or `nil`, the absence
/// of a value.
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
/// Construct a `nil` instance.
public init()
/// Construct a non-`nil` instance that stores `some`.
public init(_ some: Wrapped)
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
@warn_unused_result
public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
/// Returns `nil` if `self` is `nil`, `f(self!)` otherwise.
@warn_unused_result
public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}