Swift-奇奇怪怪的符号

简单的数据压缩 简单的数据压缩 压缩实际上就是一种节省空间的行为,比如一个字符占8位,当我们需要用一串字符来记录某种信息时,所占大小就是字符数x8.比如现在需要记录某一串遗传信息核苷酸ATCG。 eg:ATCGATTCTG 则需要10x8 = 80位。 因为以上的字符比较特殊,它是只有4个符号组成,那么我们约定:用2位存储来指代上面的其中一个符号,则就能达到节省空间的目的。 eg:A:00 T:01 C:10 G:11 那么上述字符串就能压缩成:00011011000101100111,只需要10x2=20位就能完成 阅读详情

?- 可选类型

? 在Swift语言中对一种可选类型(Optional)操作的语法糖,可以用 ? 来表示“有一个值,值是什么”或者“没有值,值是nil”。

var A_nil: Int? = nil
var A: Int? = 10
var A_other: Int = nil // 'nil' cannot initialize specified type 'Int'

这里我们可以看到可选类型的变量既可以设置为有值类型,也可以设置为nil类型,但是A_other设置为nil,程序就会报错,nil不能初始化指定类型Int。

那可选类型的本质是什么呢?

var A: Int? = 10
var A_optional: Optional<Int> = 10

这里我们可以发现,类型(Optional)的定义就是通过在类型声明后加一个 ? 操作符完成的,它们的作用是等价的,我们可以看看Optional底层的源码是什么样的,这里是swift5的源码:

@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {

    /// 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.
    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)

    ...

    /// The wrapped value of this instance, unwrapped without checking whether
    /// the instance is `nil`.
    ///
    /// The `unsafelyUnwrapped` property provides the same value as the forced
    /// unwrap operator (postfix `!`). However, in optimized builds (`-O`), no
    /// check is performed to ensure that the current instance actually has a
    /// value. Accessing this property in the case of a `nil` value is a serious
    /// programming error and could lead to undefined behavior or a runtime
    /// error.
    ///
    /// In debug builds (`-Onone`), the `unsafelyUnwrapped` property has the same
    /// behavior as using the postfix `!` operator and triggers a runtime error
    /// if the instance is `nil`.
    ///
    /// The `unsafelyUnwrapped` property is recommended over calling the
    /// `unsafeBitCast(_:)` function because the property is more restrictive
    /// and because accessing the property still performs checking in debug
    /// builds.
    ///
    /// - Warning: This property trades safety for performance.  Use
    ///   `unsafelyUnwrapped` only when you are confident that this instance
    ///   will never be equal to `nil` and only after you've tried using the
    ///   postfix `!` operator.
    @inlinable public var unsafelyUnwrapped: Wrapped { get }

    ...
}

这里截取了一部分,我们可以看到:

  • Optional其实是一个标准库的一个enum类型
  • <Wrapped>泛型,也就是包装实际类型的数据类型
  • 遵守ExpressibleByNilLiteral,允许nil来初始化一个类型
  • none 和some两种类型,Optional.none就是nil , Optional.some就是实际值
  • 泛型属性unsafelyUnwrapped,理论上就是调用unsafelyUnwrapped获取可选项的实际的值,这种值不安全的
    这里我们用枚举来匹配对应的值:
var A: Int? = 10

// 匹配有值和没值两种情况
switch A {
    case .none:
        print("nil")
    case .some(let value):
        print(value)
}

! - 强制解析

当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号!来获取值,这个感叹号表示"可选值有值"。我们称之为强制解析(forced unwrapping)

var A: Int? = 10

print(A!)
print(A.unsafelyUnwrapped)

这里我们看到A的值都能打印出10,unsafelyUnwrapped和强制解包操作符 ! 具有相同的值,但是unsafelyUnwrapped是不安全的

var A: Int? = nil

print(A!)
print(A.unsafelyUnwrapped)

这里都会出现崩溃,崩溃的信息分别是

Fatal error: Unexpectedly found nil while unwrapping an Optional value
// 致命错误:解包装可选值时意外发现nil
Fatal error: unsafelyUnwrapped of nil optional
// 致命错误:无可选的不安全解包

根据报错的信息我们可以看到unsafelyUnwrapped是不安全的解包,这里我们看一下官方文档的解释:

unsafelyUnwrapped官方解释

这里我们来验证一下unsafelyUnwrapped的不安全性,首先我们先设置一下 -O 这个优化级别,这里的-O是指target -> Build Setting -> Optimization Level设置成-O时。release模式默认是Fastest, Smallest[-Os],将运行模式调整为release模式,按照下面代码重新运行:


let A: Int? = nil

print(A!)
// print(A.unsafelyUnwrapped)

print("----")

此时出现崩溃,我们通过打印,可以看到相关的错误信息,说明强制解析可以检查确保当前的实际的值,错误信息也会正常打印检测:

截屏

相反我们使用unsafelyUnwrapped:

截屏

这里我们可以看到并没有出现崩溃信息,没有检查确保当前实际的值,这种是很不安全的。

??- 空合运算符

空合运算符(a ?? b)将可选类型a进行空判断,如果a包含一个值就进行解包,否则就返回一个默认值b。表达式a必须是Optional类型。默认值b的类型必须要和a存储值的类型保持一致。
我们可以用三元运算符表达:

a != nil ? a! : b

以上是一个三元运算符,当可选值a不为空时,对其进行强制解包a!以访问a中的值;反之默认返回b的值。如果b是一个函数,也就不会执行了。
我们点开源码分析一下:

...
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T

...
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?

通过源码,我们可以看到:

  • <T>泛型
  • 第一个变量optional,是一个T?类型
  • 第二个变量defaultValue,默认值,通过@autoclosure修饰,自动转换成了一个闭包。比如"X",就会被封装成{return "X"},这里defaultValue不是一个值,而是一个函数,这样一来,我们可以在需要的时候再执行这个函数,而不需要的话,就不执行。
    如果我们这里设置defaultValue是T类型呢?我们自定义自己的符号运算符???来验证这个问题:
func A() -> String{
    print("A is called!!!")
    return "A"
}

func B() -> String{
    print("B is called!!!")
    return "B"
}

infix operator ???

func ???<T>(optional: T? , defaultValue: T) -> T{
    if let value = optional{ return value }
    return defaultValue
}

let AorB = A() ??? B()

结果是:

A is called!!!
B is called!!!

很显然A和B都执行了,不符合空值运算符的特性,然后我们将defaultValue设置为闭包类型,用@autoclosure修饰:

func A() -> String{
    print("A is called!!!")
    return "A"
}

func B() -> String{
    print("B is called!!!")
    return "B"
}

infix operator ???

func ??? <T>(optional: T?, defaultValue: @autoclosure () -> T) -> T {
    if let value = optional{ return value}
    return defaultValue()
}

let AorB = A() ??? B()
let AorX = A() ??? "X"

这里的结果如下:

A is called!!!
A is called!!!

可以看到,optional执行后,defaultValue就不会执行,如果你本身就是闭包(或者函数),非常好,你将享受这种延迟调用带来的优势;但如果你不是闭包,你将被自动封装成闭包,同时也享受了这种延迟调用带来的性能提升!,这里"X"就会自动被封装成{return "X"},如果这里的X不是string类型,而是其他类型,空合运算符前后数据类型不一致,就会导致崩溃。

$0- 闭包简化参数名

Swift 自动对行内闭包提供简写实际参数名,可以通过$0$1$2 等名字来引用闭包的实际参数值。

let numbers = [1,2,3,4,5]

let sortNum = numbers.sorted(by: {(a, b) -> Bool in
    return a > b
})
print(sortNum)

// 尾随闭包写法
let sortNum2 = numbers.sorted { (a, b) -> Bool in
    return a > b
}
print(sortNum2)

let sortNum3 = numbers.sorted(by: { $0 > $1 })
print(sortNum3)

// 尾随闭包写法
let sortNum4 = numbers.sorted { $0 > $1 }
print(sortNum4)

简写实际参数名的数字和类型将会从期望的函数类型中推断出来。 in 关键字也能被省略,因为闭包表达式完全由它的函数体组成

var myDict: [String: Int] = ["Li": 22,"Zhang": 28]
myDict.sorted {
    let key1 = $0.0
    let value1 = $0.1
    let key2 = $1.0
    let value2 = $1.1
    print(key1,value1,key2,value2)
    return true
}

$0是传递给closure的第一个参数的简写名称,在这种情况下,当您映射一个Dictionary时,该参数是一个元组,因此$0.0是第一个一个键,$0.1是第一个值
这里的输出结果是:

Li 22 Zhang 28

为什么你的ESXI无法识别移动硬盘?一步步教你解决USB存储挂载问题 本文深入解析了ESXi无法识别移动硬盘的根本原因,并提供了从诊断到解决的完整方案。核心在于理解ESXi的USB Arbitrator服务机制,通过检查服务状态、内核设备识别及分区表,逐步定位问题。文章详细指导了如何禁用USB仲裁服务以在主机挂载USB存储,或将其直通给虚拟机,并针对大容量硬盘、USB 3.0兼容性等进阶问题给出了实用建议。 阅读详情

相关推荐

【STM32+K210项目】基于K210智能人脸识别+车牌识别系统(完整工程资料源码)

随着时代的进步和科技的迅猛发展,人们对居住安全的重视程度不断提升,对安全防范系统的需求也日益增强。在安防系统中,门禁系统占据着重要的位置。传统的门禁控制方式主要依靠钥匙、密码和门禁卡等,这些方式易于被破解和复制,安全性较低。然而,近年来,生物识别技术的迅速发展和成熟,为解决这一问题提供了新的方案。生物识别技术具备便携性、非易失性、不易遗忘以及难以盗用等优点,逐渐被引入到门禁系统中。传统的小区门禁系统往往依赖人工管理,存在一定的局限性,难以满足用户多样化的需求,也浪费了人力资源。

嵌入式技术开发 1万+

@frozen SwiftSwiftUI中文文档手册)

@frozen 将此属性应用于结构或枚举声明,以限制可以对类型进行更改的种类。仅在库演化模式下编译时才允许使用此属性。library的未来版本无法通过添加,删除或重新排列枚举的案例或结构的存储实例属性来更改声明。非冻结类型允许进行这些更改,但它们会破坏冻结类型的ABI兼容性。 注意,当编译器不处于库演化模式时,所有结构和枚举都将隐式冻结,并且将忽略此属性。 在库演化模式下,与非冻结结构和枚举进...

iCloudEnd的博客 1505

API 653 -2025 储罐检查、修理、改造和重建.rar

API 653 -2025 储罐检查、修理、改造和重建.rar

Swift中的frozen关键字

它通过限制类型的继承和扩展,允许编译器做出更为积极的优化。它的作用是告诉编译器,某个类或结构体是不可扩展的,意味着这个类型不会再被子类化或修改,这样编译器可以做出一些优化。

我叫柱子哥 719

Swift - 多类型和容器

Swift 中有两个原生的容器类型,Array和Dictionary: @frozen public struct Array<Element> { } @frozen public struct Dictionary<Key, Value> where Key : Hashable { } 它们都是泛型的,也就是说我们在一个集合中只能放同一个类型的元素,比如: let numbers = [1, 2, 3, 4, 5] // numbers 的类型是[Int]

HumorousGhost 696

Swift进阶黄金之路(二)

Swift进阶黄金之路(一) 上期遗留一个问题:为什么 rethrows 一般用在参数中含有可以 throws 的方法的高阶函数中。 我们可以结合Swift的官方文档对rethrows再做一遍回顾: A function or method can be declared with the rethrows keyword to indicate that it throws an error...

iOS成长之路 1613

swift官方文档_今年的 Swift,有哪些新的东西呢?

苹果官方在美国当地时间 9.20在 Swift 官方正式官宣了 Swift 5.1。Swift 5.1在Swift 5的基础上扩展了语言的稳定功能。不过等等,本文不是对官宣文档的整理,而是整理自 Xcode 11 release note。Xcode 11 中对 Swift 的支持也有部分更新,包括一些新特性和修复了一些问题。我们在此将与 Swift 相关的内容独立出来。主要是 Swi...

weixin_39631295的博客 243

c,oc,和swift

本篇文章的出发点是 C 语言,作为经典的过程式编程语言,它提供了最基本的编程模型:包括输入输出、函数定义、条件与循环、指针操作等我们将以 C 语言的基本语法结构为“骨架”,逐项展开,比较 Objective-C 和 Swift 这两种现代语言在实现相同功能时的写法与机制差异换言之,本篇不是简单罗列三种语言的语法形式,而是以 C 语言为基础,探究在其他语言中如何实现相似功能,以及语言设计背后的理念与机制。

liusir0324的博客 651

Swift核心设计哲学:类型契约、值语义与可选类型三大范式

Swift并非单纯语法更简洁的Objective-C替代品,而是一门以‘安全即默认’为底层逻辑的现代系统级编程语言。其核心在于编译期强制的类型契约(Type as Contract),通过类型推断与类型安全消除隐式转换风险;以值语义优先(Value Semantics First)配合Copy-on-Write机制,在保障数据隔离性的同时兼顾性能;并将空值(nil)升格为显式状态(Nil as State),借由Optional类型和可选绑定将不确定性纳入编译检查范畴。这些设计共同支撑起iOS/macOS平

diaoqi6581的博客 438

Day07:运算符

摘自杨杰老师:运算符

qq_34491373的博客 693

Swfit 常用特性(Attribute)关键字

Swfit 常用特性(Attribute)关键字 Swift中的Attribute相当于Java中的注解,但是可惜的是目前Swift不支持自定义Attribute Swfit的特性关键字一般用于声明或者用于类型 使用形式 @属性关键字 或者带参数@属性(参数) @availabel @available用来标识 计算属性(不包含储存属性)、函数、类、结构体、枚举等声明周期(依赖特定版本或者Swif...

小桥流水哗啦啦,iOS Coder 哒哒哒 1166

Swift中$0、$1的实际含义

swift 自动为闭包提供了参数缩写功能,可以直接通过 0和0和0 和1等来表示闭包中的第一个第二个参数,并且对应 的参数类型会根据函数类型来进行推断。如下代码: 不使用 000 1来代替闭包参数 let sortedArray = [2,3,5,6,7] let tempSum = sortedArray.sorted { (a, b) -&amp;gt; Bool in retu...

daiqiao_ios的博客 5575

[译] Swift 5 中的枚举冻结

原文地址:Swift 5 Frozen enums 原文作者:Keith Harrison 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:iWeslie 校对者:Lobster-King 你是否已经将你的 Xcode 工程升级到了兼容 Swift 5?升级 Swift 5 基本不会有大问题,但当你用 switch 语句去枚举一个未知值的时候可能...

weixin_34279246的博客 1040

Swift 5.0 值得关注的特性:Handle unknown values using "@unknown default"

swift 升级到 5.0 的时候相信大家一定会遇到建议添加 @unknown default 的警告: @unknown default 解决的两个问题 未来增加新的 case 后不会影响原有代码的编译 如果 switch 语句中覆盖了枚举的每个 case,那么未来这个枚举如果增加了一个值,一定会对原来调用的代码造成 break change。如果是我们自己定义的枚举还好改,如果是系统级的...

weixin_34168700的博客 470

Swift 5 枚举

枚举 关联值: 枚举的成员值和其他类型的值关联储存,存储在枚举变量中 enum Date { case digit(year: Int, month: Int, day: Int) case string(String) } var date = Date.digit(year: 2019, month: 12, day: 31) date = .string("...

u011307204的博客 440

Swift - 泛型扩展

Swift 对于泛型的支持使用我们可以避免为类似的功能多次书写重复的代码,这是一种很好的简化。而对于泛型类型,我们也可以使用extension 为泛型类型添加新的方法。 与为普通的类型添加扩展不同的是,泛型类型在类型定义时候就引入了类型标志,我们可以直接使用。例如Swift 的Array 类型的定义是: @frozen public struct Array<Element> { } 在这个定义中,已经声明了Element 为可变类型。在为类似这样的泛型类型写扩展的时候,我们不需要在exte

HumorousGhost 752

Swift面试资料 (二) —— Questions 和 Answers(二)

版本记录 版本号 时间 V1.0 2019.04.24 星期三 前言 Swift作为一门开发语言,它到目前为止也四岁了,接下来这个专题主要收集一下Swift面试相关的问题。感兴趣的看下面几篇文章。1. Swift面试资料 (一) —— Questions 和 Answers(一) Intermediate Written Questions 现在,加快一点难度。 你准备好了吗? 1. Question #1 nil和.none之间有什么区别? 没有区别,因为Optio

流浪(WESTKING)的专栏 436

快速浏览Swift-笔记

快速浏览Swift-笔记 快速浏览Swift:https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html 变量也常量 // 多行字符串,使用 “”" “”" let quotation = """ I said "I have \(3) apples." And then I said "I have \(3 + 4) pieces of fruit." """ print(quotation) // 创建一个空数组,可变的 var arra

竹毛言己 271

swift语言中的三个知识点(可选类型、可选绑定、nil)

1.使用可选类型(opitionals)来处理值可能确实的情况,可选类型表示: 有值,等于x 没有值 比如下面的一个列子: let possibleNumber = “123” let convertedNumber = possibleNumber.toInt 这个例子中常量possibleNumber有可能是一个不单单含有数字的字符串,如果统一转成Int类型有可能会失败,所以swift就产生了一

王绵杰的个人博客 4523

Swift4.0字段取值判断为nil null

当我们从接口中请求到数据时, 如果服务端没有考虑到某个字段为空的情况下, 此时就会将该字段的空值返回过来, 或者恰好我们之前用到了这个字段, 由于后期的迭代不需要这个字段了, 那么此时的代码中再去取这个字段无疑会崩溃, 所以为了避免这种事情发生有以下种处理方式: 1.在创建模型的时候给个默认值 2.即使没有给默认值,那就稍微麻烦一点将返回的字典取值时判断 if dics!["re...

李小源的博客 7400

Swift中的nil

Swift中的nil和OC中的nil不一样。OC中的nil表示不存在的对象,你无法给NSInteger类型的变量赋值nil,但是Swift中的nil表示不存在,可以给任何Optional的变量或者常量赋nil,即使是普通类型: var a: Int? = nil let b: Double? = nil 但是,需要注意的是,无法给非Optional类型的变量或者常量赋nil: va...

chaoguo1234的专栏 1369
上一篇: 手动设置ip 访问内网地址
下一篇: Swift 之 as区别
有没有人告诉你
博客等级 码龄13年 126粉丝 314原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值