详细讲解Swift中的类型占位符

Swift 的类型推断能力从一开始就是语言的核心部分,它极大地减少了我们在声明有默认值的变量和属性时手动指定类型的工作。例如,表达式var number = 7不需要包含任何类型注释,因为编译器能够推断出值7是一个Int,我们的number变量应该被相应的类型化。

作为 Xcode 13.3 的一部分而一起发布的 Swift 5.6,通过引入 "类型占位符(type placeholders) "的概念,继续扩展这些类型推理能力,这在处理集合和其他通用类型时非常有用。

例如,假设我们想创建一个Combine里面具有默认整数值的 CurrentValueSubject的实例。关于如何做到这一点的初步想法可能是简单地将我们的默认值传递给该主体的初始化器,然后将结果存储在本地的一个let声明的属性中(就像创建一个普通的Int值时一样)。然而,这样做会给我们带来以下编译器错误:

// Error: "Generic parameter 'Failure' could not be inferred"
// Error: “无法被推断出泛型的`Failure`参数 ”
let counterSubject = CurrentValueSubject(0)

这是因为CurrentValueSubject是一个泛型类型,实例化时不仅需要Output类型,还需要Failure类型——这是该主体能够抛出的错误类型。

因为我们不希望我们的主体在这种情况下抛出任何错误,所以我们会给它一个Failure类型的值Never(这是在 Swift 中使用 Combine 的一个常见惯例)。但为了做到这一点,在 Swift 5.6 之前,我们需要明确地指定我们的Int输出类型——像这样:

let counterSubject = CurrentValueSubject<Int, Never>(0)

不过从 Swift 5.6 开始,这种情况就不存在了——因为我们现在可以使用一个类型占位符来表示我们主体的Output类型,这让我们再次利用编译器为我们自动推断出该类型,就像在声明一个普通的Int值一样:

let counterSubject = CurrentValueSubject<_, Never>(0)

这很好,但可以说这并不是 swift 里面很大的改进。毕竟,我们用_代替Int只是节省了两个字符,而且手动指定像Int这样的简单类型也不是一开始就有问题的。

**但现在让我们看看这个功能如何扩展到更复杂的类型,这是它真正开始发光的地方。**例如,假设我们的项目包含以下函数,让我们加载一个用户注解的PDF文件:

func loadAnnotatedPDF(named: String) -> Resource<PDF<UserAnnotations>> {
    ...
}

上面的函数使用了一个相当复杂的泛型作为它的返回类型,这可能是因为我们需要在多个地方中重复使用我们的Resource类型,也因为我们选择了使用*幻象类型*来指定我们当前处理的是哪种PDF。

现在让我们看看,如果我们在创建主体时调用上述函数,而不是仅仅使用一个简单的整数,那么我们之前基于CurrentValueSubject的代码会是什么样子:

// Before Swift 5.6:
let pdfSubject = CurrentValueSubject<Resource<PDF<UserAnnotations>>, Never>(
    loadAnnotatedPDF(named: name)
)

// Swift 5.6:
let pdfSubject = CurrentValueSubject<_, Never>(
    loadAnnotatedPDF(named: name)
)

这是一个相当大的改进啊 基于 Swift 5.6 的版本不仅为我们节省了一些输入,而且由于 pdfSubject 的类型现在完全来自 loadAnnotatedPDF 函数,这可能会使该函数(及其相关代码)的迭代更加容易——因为如果我们改变该函数的返回类型,需要更新的手动类型注释将减少。

不过,值得指出的是,在上述情况下,还有另一种方法可以利用Swift的类型推理能力——那就是使用类型别名,而不是类型占位符。例如,我们可以在这里定义一个UnfailingValueSubject类型别名,我们可以用它来轻松地创建不会产生任何错误的主体:

typealias UnfailingValueSubject<T> = CurrentValueSubject<T, Never>

有了上述内容,我们现在就可以在没有任何泛型注解的情况下创建我们的pdfSubject了——因为编译器能够推断出T指的是什么类型,而且失败类型Never已经被硬编码到我们的新类型别名中:

let pdfSubject = UnfailingValueSubject(loadAnnotatedPDF(named: name))

但这并不意味着类型别名在通常情况下都比类型占位符好,因为如果我们要为每种特定情况定义新的类型别名,那么这也会使我们的代码库变得更加复杂。有时,在内联中指定所有的东西(比如使用类型占位符时)绝对是个好办法,因为这可以让我们定义完全独立的表达式。

在我们总结之前,让我们也来看看类型占位符是如何与集合字面量(literals)一起使用的——例如在创建一个字典时。在这里,我们选择手动指定我们的字典的 Key 类型(为了能够使用点语法来指代枚举的各种情况),同时为该字典的值使用一个类型占位符:

enum UserRole {
    case local
    case remote
}

let latestMessages: [UserRole: _] = [
    .local: "",
    .remote: ""
]

这就是类型占位符——Swift 5.6 中引入的一个新功能,在处理稍微复杂的通用类型时,它可能真的很有用。但值得指出的是,这些占位符只能在调用站点使用,而不是在指定函数或计算属性的返回类型时使用。

总结

到此这篇关于Swift类型占位符的文章就介绍到这了,更多相关Swift类型占位符内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Swift教程之基础数据类型详解

    基础类型 虽然Swift是一个为开发iOS和OS X app设计的全新编程语言,但是Swift的很多特性还是跟C和Objective-C相似. Swift也提供了与C和Objective-C类似的基础数据类型,包括整形Int.浮点数Double和Float.布尔类型Bool以及字符串类型String.Swift还提供了两种更强大的基本集合数据类型,Array和Dictionary,更详细的内容可以参考:Collection Types. 跟C语言一样,Swift使用特定的名称来定义和使用变量.同

  • Swift编程中的一些类型转换方法详解

    验证一个实例的类型'类型转换'在 Swift 语言编程中.它是用来检查实例类型是否属于特定超类或子类或其自己的层次结构定义. Swift 类型转换提供两个操作符:"is" 检查值的类型和 'as' 将类型值转换为不同的类型值. 类型转换还检查实例类型是否符合特定的协议一致性标准. 定义一个类层次结构 类型转换用于检查实例的类型或者它属于特定类型.此外,检查类和它的子类层次结构来检查并转换这些实例,使之作为一个相同的层次结构. 复制代码 代码如下: class Subjects {   

  • Swift教程之集合类型详解

    Swift 提供两种集合类型来存储集合,数组和字典.数组是一个同类型的序列化列表集合.字典是一个能够使用类似于键的唯一标识符来获取值的非序列化集合. 在Swift中,数组和字典的键和值都必须明确它的类型.这意味这数组和字典不会插入一个错误的类型的值,以致于出错.这也意味着当你在数组和字典中取回数值的时候能够确定它的类型. Swift 使用确定的集合类型可以保证代码工作是不会出错,和让你在开发阶段就能更早的捕获错误. note: Swift的数组 储存不同的类型会展示出不同的行为,例如变量,常量或

  • 详细讲解Swift中的类型占位符

    Swift 的类型推断能力从一开始就是语言的核心部分,它极大地减少了我们在声明有默认值的变量和属性时手动指定类型的工作.例如,表达式var number = 7不需要包含任何类型注释,因为编译器能够推断出值7是一个Int,我们的number变量应该被相应的类型化. 作为 Xcode 13.3 的一部分而一起发布的 Swift 5.6,通过引入 "类型占位符(type placeholders) "的概念,继续扩展这些类型推理能力,这在处理集合和其他通用类型时非常有用. 例如,假设我们想

  • Java超详细讲解设计模式中的命令模式

    目录 介绍 实现 个人理解:把一个类里的多个命令分离出来,每个类里放一个命令,实现解耦合,一个类只对应一个功能,在使用命令时由另一个类来统一管理所有命令. 缺点:如果功能多了就会导致创建的类的数量过多 命令模式(Command Pattern)是⼀种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调⽤对象.调⽤对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执⾏命令. 介绍 意图:将⼀个请求封装成⼀个对象,从⽽使您可以⽤不同的请求对客户进⾏参数化.

  • Java详细讲解包的作用以及修饰符的介绍

    目录 1.包 1.包的三大作用 2.包的基本语法 3.包的本质 4.包的命名规则 5.包的命名规范 6.常用的包 7.注意事项和使用细节 2.访问修饰符 1.4种访问修饰符的访问范围 2.使用注意事项 3.具体实例说明 1. 同类 2. 同包 3. 不同包子类 4. 不同包 1.包 1.包的三大作用 区分相同名字的类 当类很多时,可方便管理 控制访问范围 2.包的基本语法 package abc.www; 3.包的本质 实际上就是创建不同的文件夹/目录保存类文件 4.包的命名规则 只能包含数字,

  • 基于android布局中的常用占位符介绍

    大家在做布局文件是肯定会遇到过下面的这种情况 填充出现问题,所以需要用到占位符规范填充 汉字常用占位符: <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="这是测试:" android:textSize="22sp" /> <TextView android:layo

  • Java超详细讲解多线程中的Process与Thread

    目录 进程和线程的关系 操作系统是如何管理进程的 并行和并发 创建线程的方法 串行执行和并发执行 Thread中的一次额重要方法 中断线程 线程等待 线程休眠(sleep) 进程和线程的关系 在操作系统中运行的程序就是进程,比如说QQ,播放器,游戏等等…程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念. 进程和线程都是为了处理并发编程这样的场景,但是进程有问题,频繁拆功创建和释放资源的时候效率低,相比之下,线程更轻量,创建和释放效率更高. 进程具有独立性,每个进程有各自独立

  • iOS中修改UITextField占位符字体颜色的方法总结

    前言 最近学了UITextField控件, 感觉在里面设置占位符非常好, 给用户提示信息, 于是就在想占位符的字体和颜色能不能改变呢?下面是小编的一些简单的实现,有需要的朋友们可以参考. 修改UITextField的占位符文字颜色主要有三个方法: 1.使用attributedPlaceholder属性 @property(nullable, nonatomic,copy) NSAttributedString *attributedPlaceholder NS_AVAILABLE_IOS(6_0

  • 深入讲解Swift中的模式匹配

    模式匹配 模式匹配是 Swift 中非常常见的一种编程模式,使用模式匹配,可以帮助我们写出简明.清晰以及易读的代码,使我们的代码变得简洁而强大. 条件判断中的模式匹配 条件判断是我们使用最普遍的流程控制,在 Swift 中,只能接受 Bool 类型的值作为条件体:除了直接判断 Bool 值之外,我们还能使用使用条件语句进行可选绑定,这在我们开发中是非常常用的方式. 匹配枚举值 在 Swift 中,创建的枚举类型默认是不可比较的(没有实现Comparable协议),这就意味着我们不能直接使用==操

  • 实例讲解Swift中引用类型的ARC自动引用计数

    一.引言 ARC(自动引用计数)是Objective-C和Swift中用于解决内存管理问题的方案.在学习Objective-C编程时经常会学习到一个关于ARC的例子:在一个公用的图书馆中,每次进入一人就将卡插入,走的时候将自己的卡拔出拿走.图书馆系统会判定只要有卡插入,就将图书馆的灯打开,当所有卡都被取走后,将图书馆的灯关掉.这个例子对应于Objective-C中的对象声明周期管理十分贴切.每当一个对象增加一个引用时,其引用计数会加1,当一个引用被取消时,对象的引用计数减1,当引用计数减为0时,

  • C++ 中const 类型限定符不兼容问题

    今天在写程序的时候,出现了一个错误  "对象包含与成员函数不兼容的类型限定符",从网上查了一下,原来原因是这样子的 void showPair(); 改成 void showPair()const; 在具有 如上图所示的函数中,如果调用了其它函数,那么其它函数也必须有 const 属性,否则就会出现 类型限定符不兼容的错误! 以上所述就是本文的全部内容了,希望大家能够喜欢.

  • 深入讲解数据库中Decimal类型的使用以及实现方法

    目录 1 背景 2 Decimal类型的使用 2.1 描述Decimal 2.2 建表时定义Decimal 2.3 写入decimal数据 2.4 取出deimcal进行计算 3 Decimal类型的实现 3.1 MySQL 3.2 ClickHouse 3.3 总结 4. MySQL 违反直觉的地方 总结 1 背景 数字运算在数据库中是很常见的需求, 例如计算数量.重量.价格等, 为了满足各种需求, 数据库系统通常支持精准的数字类型和近似的数字类型. 精准的数字类型包含 int, decima

随机推荐