前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >开心档之Swift 访问控制

开心档之Swift 访问控制

原创
作者头像
爱学iOS的小麦子
发布于 2023-03-06 09:59:18
发布于 2023-03-06 09:59:18
1K00
代码可运行
举报
文章被收录于专栏:iOS开发大全iOS开发大全
运行总次数:0
代码可运行

Swift 访问控制

访问控制可以限定其他源文件或模块中代码对你代码的访问级别。

你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、函数、初始化方法、基本类型、下标索引等设置访问级别。

协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数。

访问控制基于模块与源文件。

模块指的是以独立单元构建和发布的 Framework 或 Application。在 Swift 中的一个模块可以使用 import 关键字引入另外一个模块。

源文件是单个源码文件,它通常属于一个模块, 源文件可以包含多个类和函数 的定义。

Swift 为代码中的实体提供了四种不同的访问级别:public、internal、fileprivate、private

访问级别

定义

public

可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。

internal

可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。

fileprivate

文件内私有,只能在当前源文件中使用。

private

只能在类中访问,离开了这个类或者结构体的作用域外面就无法访问。

public 为最高级访问级别,private 为最低级访问级别。

语法

通过修饰符public、internal、fileprivate、private来声明实体的访问级别:

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
 
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

除非有特殊的说明,否则实体都使用默认的访问级别 internal。

未指定访问级别默认为 internal

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SomeInternalClass {}              // 访问级别为 internal
let someInternalConstant = 0            // 访问级别为 internal

函数类型访问权限

函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。

下面的例子定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
}

函数中其中一个类 SomeInternalClass 的访问级别是 internal,另一个 SomePrivateClass 的访问级别是 private。所以根据元组访问级别的原则,该元组的访问级别是 private(元组的访问级别与元组中访问级别最低的类型一致)。

因为该函数返回类型的访问级别是 private,所以你必须使用 private 修饰符,明确的声明该函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
}

将该函数申明为 public 或 internal,或者使用默认的访问级别 internal 都是错误的,因为如果这样你就无法访问 private 级别的返回值。


枚举类型访问权限

枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。

实例

比如下面的例子,枚举 Student 被明确的申明为 public 级别,那么它的成员 Name,Mark 的访问级别同样也是 public:

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public enum Student {
    case Name(String)
    case Mark(Int,Int,Int)
}
 
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
 
switch studMarks {
case .Name(let studName):
    print("学生名: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
    print("学生成绩: \(Mark1),\(Mark2),\(Mark3)")
}

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
学生成绩: 98,97,95

子类访问权限

子类的访问级别不得高于父类的访问级别。比如说,父类的访问级别是 internal,子类的访问级别就不能申明为 public。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SuperClass {
    fileprivate func show() {
        print("超类")
    }
}
 
// 访问级别不能高于超类 public > internal
internal class SubClass: SuperClass  {
    override internal func show() {
        print("子类")
    }
}
 
let sup = SuperClass()
sup.show()
 
let sub = SubClass()
sub.show()

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
超类
子类

常量、变量、属性、下标访问权限

常量、变量、属性不能拥有比它们的类型更高的访问级别。

比如说,你定义一个public级别的属性,但是它的类型是private级别的,这是编译器所不允许的。

同样,下标也不能拥有比索引类型或返回类型更高的访问级别。

如果常量、变量、属性、下标索引的定义类型是private级别的,那么它们必须要明确的申明访问级别为private:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private var privateInstance = SomePrivateClass()

Getter 和 Setter访问权限

常量、变量、属性、下标索引的Getters和Setters的访问级别继承自它们所属成员的访问级别。

Setter的访问级别可以低于对应的Getter的访问级别,这样就可以控制变量、属性或下标索引的读写权限。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Samplepgm {
    fileprivate var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增加数量 \(counter - oldValue)")
            }
        }
    }
}
 
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

counter 的访问级别为 fileprivate,在文件内可以访问。

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
计数器: 100
新增加数量 100
计数器: 800
新增加数量 700

构造器和默认构造器访问权限

初始化

我们可以给自定义的初始化方法申明访问级别,但是要不高于它所属类的访问级别。但必要构造器例外,它的访问级别必须和所属类的访问级别相同。

如同函数或方法参数,初始化方法参数的访问级别也不能低于初始化方法的访问级别。

默认初始化方法

Swift为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。

默认初始化方法的访问级别与所属类型的访问级别相同。

实例

在每个子类的 init() 方法前使用 required 关键字声明访问权限。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class classA {
    required init() {
        var a = 10
        print(a)
    }
}
 
class classB: classA {
    required init() {
        var b = 30
        print(b)
    }
}
 
let res = classA()
let show = classB()

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
10
30
10

协议访问权限

如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。

如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public protocol TcpProtocol {
    init(no1: Int)
}
 
public class MainClass {
    var no1: Int // local storage
    init(no1: Int) {
        self.no1 = no1 // initialization
    }
}
 
class SubClass: MainClass, TcpProtocol {
    var no2: Int
    init(no1: Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    
    // Requires only one parameter for convenient method
    required override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}
 
let res = MainClass(no1: 20)
let show = SubClass(no1: 30, no2: 50)
 
print("res is: \(res.no1)")
print("res is: \(show.no1)")
print("res is: \(show.no2)")

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
res is: 20
res is: 30
res is: 50

扩展访问权限

你可以在条件允许的情况下对类、结构体、枚举进行扩展。扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的internal访问级别。

或者,你可以明确申明扩展的访问级别(比如使用private extension)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖。


泛型访问权限

泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public struct TOS<T> {
    var items = [T]()
    private mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
}
 
var tos = TOS<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("泛型")
print(tos.items)
 
tos.push("类型参数")
print(tos.items)
 
tos.push("类型参数名")
print(tos.items)
let deletetos = tos.pop()

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "类型参数"]
["Swift", "泛型", "类型参数", "类型参数名"]

类型别名

任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。

比如说,一个private级别的类型别名可以设定给一个public、internal、private的类型,但是一个public级别的类型别名只能设定给一个public级别的类型,不能设定给internal或private 级别的类型。 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。

实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}
 
struct Stack<T>: Container {
    // original Stack<T> implementation
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
    
    // conformance to the Container protocol
    mutating func append(item: T) {
        self.push(item)
    }
    
    var count: Int {
        return items.count
    }
    
    subscript(i: Int) -> T {
        return items[i]
    }
}
 
func allItemsMatch<
    C1: Container, C2: Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
    (someContainer: C1, anotherContainer: C2) -> Bool {
        // check that both containers contain the same number of items
        if someContainer.count != anotherContainer.count {
            return false
        }
        
        // check each pair of items to see if they are equivalent
        for i in 0..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // all items match, so return true
        return true
}
 
var tos = Stack<String>()
tos.push("Swift")
print(tos.items)
 
tos.push("泛型")
print(tos.items)
 
tos.push("Where 语句")
print(tos.items)
 
var eos = ["Swift", "泛型", "Where 语句"]
print(eos)

以上程序执行输出结果为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
["Swift"]
["Swift", "泛型"]
["Swift", "泛型", "Where 语句"]
["Swift", "泛型", "Where 语句"]

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
CODING DevOps 系列第三课:云计算、云原生模式下 DevOps 的建设
本文首先会和大家分享当前整个应用生命周期的演变历程,然后讲解云计算模式下 DevOps 建设包含的过程、流程规范和标准,最后讲解云原生时代到来会带来哪些改变,以及标准化的建设会有哪些改变和突破。
腾讯云 CODING
2020/06/16
8910
云计算、云原生模式下 DevOps 的建设
企业数字化转型过程和云的迭代发展是相互作用的。在2007年之前主要用物理机来作为我们当前应用的载体。而在2007年,KVM诞生,它能让底层操作系统和一些虚拟的网络设备做一些虚拟化的输出。2007年-2010年是虚拟化发展较好的周期,VMware和openstack是当时的代表生态。到了2013年Docker开服,云计算迎来了蓬勃发展的周期。2014年,企业的部分业务开始逐步迁移云上。2017年后到今天为止,在云原生的模式下,开发人员或者整个it部门更聚焦在业务的发展上,所有我们不关心的部分可以全部由云来管理。云开发不必关系开发在哪里,云服务不关心调用到哪里,而云资源方面也不用关心运行到了哪里。这就是从基础设施上云到业务上云,再到当前的全栈云,这样的一条全企业数字化转型之路。
云大学小编
2020/06/17
1.5K0
云计算、云原生模式下 DevOps 的建设
云原生应用交付平台Orbit设计理念与价值主张
Orbit 是腾讯云 CODING 推出的一个企业级云原生应用交付平台(图3-1)。Orbit 以应用为中心进行设计,主要包括应用建模、应用交付、应用运维和声明式基础设施设施交付 4 个方面进行平台设计,围绕着基于 OAM 应用建模、Application As Code、GitOps 版本化管理、统一可观测性 4 个维度进行具体价值主张声明。
腾讯云 CODING
2023/06/21
3K0
云原生应用交付平台Orbit设计理念与价值主张
​「DevOps 转型与实践」沙龙回顾第二讲
本期分享内容为 《平台化 DevOps—云计算与云原生模式下 DevOps 的建设实践》。目前,DevOps 越来越成为大家当前建设的热点,伴随着基础设施的转型和应用框架的转型,更多的业务偏向云端和 C 端的场景,促进了 DevOps 的发展。在本次沙龙上,腾讯云 CODING DevOps 资深架构师余朋飞为大家介绍了在云计算和云原生两种模式下,如何推进 DevOps 的建设和实践。
腾讯云 CODING
2020/10/09
4040
十六年所思所感,聊聊这些年我所经历的 DevOps 系统
前不久,我因为运动时的姿势不对,导致右腿骨折,喜提三个月的居家修养。按照作家刘震云的说法,这叫做着正确的事情,却迈着不正确的步伐。于是乎,我的活动空间骤减,每日除了短暂地楼下放风,便是卧坐于方寸之间。周遭静下来,许多回忆便涌了上来。
用户1107783
2024/09/06
1510
十六年所思所感,聊聊这些年我所经历的 DevOps 系统
金融云原生漫谈(一)|银行业如何快速提升应用研发效能和交付效率?
在金融行业数字化转型的驱动下,国有银行、股份制银行和各级商业银行也纷纷步入容器化的进程。如果以容器云上生产为目标,那么整个容器云平台的设计、建设和优化对于银行来说是一个巨大的挑战。如何更好地利用云原生技术,帮助银行实现敏捷、轻量、快速、高效地进行开发、测试、交付和运维一体化,从而重构业务,推动金融科技的发展,是个长期课题。
灵雀云
2021/12/17
6220
​「DevOps 转型与实践」沙龙回顾第一讲
9 月 19 日,CODING 和中国 DevOps 社区联合举办的深圳第九届 Meetup 在腾讯大厦 2 楼多功能圆满结束。本次沙龙以 「DevOps 转型与实践」 为主题,4 位来自互联网、金融、零售行业的知名世界 500 强企业技术大咖,在现场分享了他们对于 DevOps 转型实践的见解和经验。80 多位观众与讲师们也进行了深入的技术探讨,共同探讨在 DevOps 潮流下,企业可能面临的新机遇和挑战。
腾讯云 CODING
2020/10/09
8130
蓝鲸DevOps深度解析系列(1):蓝盾平台总览
2018年10月,嘉为科技与腾讯云、蓝鲸智云携手,在北京、上海、广州、深圳举办 “研运一体,数据驱动,让运维走向运营”为主题的分享会,来自金融、电力、能源、制造等行业的数百家企业到场参加。
嘉为蓝鲸
2018/12/21
10.7K1
创新券商如何借道云原生实现进阶?
选择SpringCloud还是k8s,这也许不是关乎生死的哈姆雷特式诘问,但技术路线的抉择对整个开发进程乃至业务运行的影响,确实巨大而深远。
IT创事记
2022/08/30
3950
创新券商如何借道云原生实现进阶?
效能时代,数栈专属DevOps跑出加速度
互联网的发展形同潮水,来势汹汹、快而迅猛,企业业务日益庞大的同时伴随着团队规模的扩大,业务的复杂度与关联性显著提升的同时对效能也有了更高的要求,高效协同之间,我们既要追求快速交付,亦要保证产品的质量与稳定,两者之间产生了矛盾。DevOps作为这个矛盾平衡点,其概念最早于2009年被提出,并在近几年受到企业广泛的关注与实践。促使DevOps近年高频出现的原因,我们总结出以下两点:
袋鼠云数栈
2022/02/14
4390
深度好文|探寻云原生时代应用研发新模式
引言:伴随着基础设施技术升级,应用研发环境也从最初的传统 IT 架构、虚拟化 & 容器化架构演变到现在的云原生多云架构。“应用研发新模式”本身就是一个比较大的话题,我们也不敢说一个人或者一个团队就能把这个话题聊透彻。但随着应用研发基础架构环境的演进,应用研发模式一定是在不断地调整和创新。
开源小E
2022/04/12
5000
深度好文|探寻云原生时代应用研发新模式
传统企业 DevOps 基础设施架构规划之道
我们都知道 DevOps 诞生于互联网企业。Netflix、AWS等互联网企业号称每天往生产环境部署成百上千次。如此之快的部署频率让众多传统企业垂涎欲滴。所以大量的传统企业都纷纷投入巨资打造自己的 DevOps 基础设施 ,希望就此可以显著提高开发效率,加快新项目或新产品的投产速度。但是,他们对于 DevOps 基础架构是什么样子,需要具备哪些能力,如何构建,并没有一个很清晰的规划。
DevOps时代
2019/05/17
8600
当DevOps邂逅云原生
乌云笼罩下还敢谈创业?面对生存,小型创新企业如何把握领跑的机会 同样面临转型,为什么别人是华丽转身响彻寰宇,而你却东张西望波澜不起。悄悄告诉你,越来越多的企业的注意力转移到了客户和业务之间的交付价值,“精益求精,降本增效”真的像躺着赚钱一样不切实际嘛?不,不是你太接地气,是你的眼神疏漏犀利。突如其来的云原生带你细化云时代下企业转型的重要支撑点,窥探开发团队低效的根本原因,和DevOps手牵手,助你一直走。
可可爱爱没有脑袋
2019/12/19
1.6K0
当DevOps邂逅云原生
持续拥抱云原生,现代化应用将把云计算带进怎样的“新世界”?
云上的IT架构及服务创新,让传统私有部署模式望尘莫及。从虚拟机到容器,云计算通过不断细化服务颗粒度,持续刷新其降本提质增效的魔力。
科技云报道
2022/04/16
5580
持续拥抱云原生,现代化应用将把云计算带进怎样的“新世界”?
【Techo Day腾讯技术开放日】从大咖眼中读到腾讯云原生发展新机遇
通过周末两天对Techo Day腾讯技术开放日视频的学习,让我对云原生全栈开发的了解进一步加深,原来云原生如此高大上,又或者云原生原来如此 just so so~,无处不在的云原生到底怎样在影响开发者,面对云原生这种时代洪流,我们又应该怎样面对,下面我主要通过对各位专家老师的资料来展开论述,畅谈一下我眼中对云原生的新认识。
炒香菇的书呆子
2022/11/06
1.7K0
【Techo Day腾讯技术开放日】从大咖眼中读到腾讯云原生发展新机遇
《DevOps权威指南》电子试读版-第一章-DevOps的价值
通过对DevOps的概念、理念、发展轨迹、特点、总体架构与流程,以及实践过程中的工具链框架的打造和实践原则的描述,最终锚定DevOps的价值。随着DevOps原生理念的延伸,DevOps的价值变得更为丰富,无论是IT组织的各能力子域、IT组织自身,还是企业,均获得相应的收益。对于企业,产品的创新和市场占有率都需要IT组织的支撑能力和创新能力的提高。对于IT组织,IT能力决定了业务开展的深度和广度,自身的能力输出需要匹配甚至超越企业的业务发展。在IT组织内部的各能力子域,需要对IT能力输出负责,研发体系的敏捷,信息系统的安全、稳定和可靠,产品需求的精准,以及项目管理的完善和严谨都是必备条件。因此,在本章中,针对DevOps,我们将从多个维度对价值进行论述,对实践和落地过程提供锚定的指引。
顾黄亮
2022/01/09
6401
《DevOps权威指南》电子试读版-第一章-DevOps的价值
云原生背景下的运维价值思考与实践
作者:刘天斯,腾讯游戏高级工程师 前言 随着公司自研上云战略如火如荼地进行,IEG-增值服务部作为较早一批响应的团队,截止目前自研上云已完成1/3的流量切换,日PV超百亿。切云的服务大量采用了云原生的应用与技术架构,作为公司第一批面临云原生环境的业务运维,深切感受到云原生给运维工作带来的机遇与挑战,运维模式的转型已经迫在眉睫,此篇文章最大的价值在于将我们的转型思路、方法与实践,提供给后面更多面临同样挑战的团队借鉴与参考。下面我将从业务场景、运维转型之道、云端收益等几个方面来跟大家一起来探讨。 一、业务服
腾讯技术工程官方号
2020/11/27
2K0
CODING —— 云原生时代的研发工具领跑者
大家上午好,很高兴能有机会与大家分享 CODING 最近的一些新动作。今天主要分享的内容是 CODING 的战略升级和新产品介绍。在讲整个战略升级之前,我们先来讲一讲“为什么要做云原生时代的标准化工具”。大家都知道 CODING 一直在做开发者相关的工具,从代码托管开始,后来又做了 CI/CD、项目管理、制品库等等一系列工具。那么为什么我们认为在这个时代做这些工具会有更高的价值?
腾讯云 CODING
2021/10/29
1.2K0
CODING —— 云原生时代的研发工具领跑者
腾讯云小微AI语音助手云原生之路
云原生(CloudNative)是一个组合词,“云”表示应用程序运行于分布式云环境中,“原生”表示应用程序在设计之初就充分考虑到了云平台的弹性,就是为云设计的。可见,云原生并不是简单地使用云平台运行现有的应用程序,而是一种能充分利用云计算优势对应用程序进行设计、实现、部署、交付和操作的应用架构方法。
俞淦
2022/11/08
14.8K0
腾讯云小微AI语音助手云原生之路
云原生DevOps思考
经过二十多年的发展,云计算已经进入成熟阶段,成为了数字经济时代的新型信息基础设施。而云原生是一种构建和运行应用程序的方法,以充分利用云计算的优势。它包括微服务、容器、Kubernetes等技术,以支持弹性、可扩展和可移植的应用程序。是企业进行数字化转型、微服务架构转型的最佳技术实践路径,同时也成为热门领域——人工智能、大数据、边缘计算、物联网、5G、 区块链等底层平台的基础设施。
薛猫
2023/09/18
5800
云原生DevOps思考
推荐阅读
相关推荐
CODING DevOps 系列第三课:云计算、云原生模式下 DevOps 的建设
更多 >
目录
  • Swift 访问控制
    • 语法
    • 实例
    • 未指定访问级别默认为 internal
    • 函数类型访问权限
    • 枚举类型访问权限
      • 实例
    • 实例
    • 子类访问权限
    • 实例
    • 常量、变量、属性、下标访问权限
    • Getter 和 Setter访问权限
    • 实例
    • 构造器和默认构造器访问权限
      • 初始化
      • 默认初始化方法
      • 实例
    • 实例
    • 协议访问权限
    • 实例
    • 扩展访问权限
    • 泛型访问权限
    • 实例
    • 类型别名
    • 实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档