Swift 中的可选类型Optional

在 Swift 中,我们使用可选类型来表示值有可能缺失的情况。一个可选类型的值表示他有值并且值等于 x 或者他根本就没有值。

注意:
可选类型在C语言和OC语言中并不存在。OC中与可选类型意思最接近的是一个本该返回某个类型的对象的方法可以返回nilnil在此时表示没有有效值。然而,OC中的这种机制只对对象类型有效,对结构体,基本C类型和枚举等都无效。对于这些类型,当他们没有有效值的时候,OC会返回一些特殊常量(比如 NSNotFound)。这种方式假定方法的调用者知道这个特殊值并且记得去检测这个值。Swift中的可选类型不同,他可以表示任意类型的有效值缺失的情况,不需要指定一些特殊值。

下面的例子说明可选类型是如何处理有效值缺失的情况的。Swift 中的 Int 类型有一个将 String 类型的值转化为 Int 值的构造器。但是并不是每个 String 类型的值都可以转化成 Int 类型,“123” 可以被转化为 Int 类型的123,“hello world”却不能被转化为一个有效数字。

let possibleNumber = "123"
// 由于改构造器有失败的可能,所以他的返回值的类型是可选类型的 Int。
let convertedNumber = Int(possibleNumber)

一个可选类型的 Int 写作 Int?,问号表示这是一个可选类型。这个可选类型可以包含一个 Int 类型的值,或者没有值。只有这两种情况,不可以是 String 类型, Bool 类型或者其他任何类型。

nil

通过将一个可选类型的值设为 nil 来表示这个可选类型中不包含任何值。

// serverResponseCode 包含一个 Int 类型的值 404
var serverResponseCode: Int? = 404
// serverResponseCode 不包含任何值
serverResponseCode = nil
注意:
nil 只能被赋值给一个可选类型来表示值缺失的情况。不能把 nil 赋值给非可选类型的变量。如果一个变量有可能不包含值,请将其声明为可选类型。

如果你在声明一个可选类型时没有给他初始值,他会被自动设置为nil。

// surveyAnswer 的值为 nil
var surveyAnswer: String?
注意:
Swift中的 nilOC中的 nil 是不一样的。在OC中,nil 是指向一个不存在的对象的指针。在Swift中,nil 不是一个指针,他用来表示一个可选类型的变量不包含任何值的情况。任何类型的可选值都可以被设置为 nil,不是只有对象类型。

if 语句和强制解析

你可以使用 if 语句来判断一个可选类型是否有值。当一个可选类型有值的时候,他被认为是不等于 nil 的,反之,则等于 nil。

var convertedNumber = Int("123")
if convertedNumber != nil {
    print("convertedNumber contains some integer value")
}
convertedNumber = Int("hello world")
if convertedNumber == nil {
    print("convertedNumber does not contain any integer number")
}

输出结果:convertedNumber contains some integer value
        convertedNumber does not contain any integer number

如果你确定一个可选类型包含有效值,你可以在这个可选类型后面加上 ! 号来获取这个有效值。获取有效值被称为强制解析。

let convertedNumber = Int("123")
if convertedNumber != nil {
    print("convertedNumber contains some integer value of \(convertedNumber!)")
}

输出结果:convertedNumber contains some integer value of 123
注意:
强制解析一个值为nil的可选类型会引发运行时错误,导致程序崩溃。所以在使用强制解析之前,请确保该可选类型包含一个有效值。

可选绑定

使用可选类型之前,通常需要判断这个可选类型是否包含有效值,如果包含,要把这个有效值强制解析出来进行使用。可选绑定将这个过程融合到了一步里面。你可以在 if语句和 while语句中使用可选绑定。可选绑定的一般格式如下:

// someOptional 是一个可选类型。可选绑定判断这个可选类型是否包含有效值,如果包含,则将这个有效值强制解析出来赋给常量name,并且执行if语句块中的代码。
if let name = someOptional {
    // statements
}
let possibleNumber = "123"
if let actualNumber = Int(possibleNumber) {
    // 可选绑定已经将可选类型的有效值强制解析了出来,并将其赋值给actualNumber,所以actualNumber 不是一个可选类型,使用他的时候不需要在后面加 !。
    print("'\(possibleNumber)' has a integer value of \(actualNumber)")
} else {
    print("'\(possibleNumber)' can not be converted to a integer value")
}

// 执行结果:'123' has a integer value of 123

也可以在可选绑定中将强制解析出来的值赋给一个变量。如上例,如果你需要在 if语句的第一分支中改变 actualNumber 的值,那么你可以在可选绑定中将 actualNumber 声明为一个变量,使用 var 关键字。

可以将多个可选绑定写在同一个 if判断中,并使用 where 关键字来连接其他的逻辑判断语句。如下例:

if let firstNumber = Int("4"),secondNumber = Int("42") where firstNumber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}

// 执行结果: 4 < 42

where 关键字仅仅用来添加其他非可选绑定的逻辑判断,不是必须要和前面出现的可选绑定有联系。

if let firstNumber = Int("4") where 20 < 40 && 30 < 50 {
    print("firstNumber is \(firstNumber),where can append any Bool expression")
}

// 执行结果: firstNumber is 4,where can append any Bool expression

隐式解析可选类型

可选类型表示一个常量或者变量可以不包含有效值,我们一般使用可选绑定来判断和使用他的有效值。

注意:
可选类型可以是一个常量。当你将一个可选类型声明为一个常量时,如果这个可选类型没有有效值,你可以赋给他一个有效值。一旦他具有了有效值,这个有效值不可改变,也不能将其重新设置为nil

有时根据程序的结构,我们可以明显地看出当一个可选类型被设置了有效值之后,他将总是具有有效值。这种情况下,每次使用这个值都需要强制解析或者使用可选绑定就显得有点繁琐了,此时可以使用隐式解析可选类型。

声明隐式解析可选类型时在其类型名后面加上感叹号 ! 而不是问号 ?,声明之后,可以直接使用这个常量或者变量的有效值。如上所述,隐式解析可选类型适用于当一个可选类型的量一旦被设置了有效值,就会在其后的任一时间都具有有效值的情况(这个有效值可以改变,只要具有有效值即可)。

隐式解析可选类型实际上还是一个可选类型,只是使用上看起来像是非可选类型,因为使用他的有效值的时候不需要强制解析。下例演示了使用可选类型和隐式解析可选类型的区别:

let possibleNumber: String? = "An optional string"
// 获取有效值时需要在后面加上感叹号来强制解析
let forcedString: String = possibleNumner!

let assumedString: String! = "An implicitly unwrapped optional string"
// 获取有效值不需要强制解析
let implicitString: String = assumedString

你可以认为隐式解析可选类型在每一次使用他的时候,都会被自动解析出来。

注意:
如果一个隐式解析可选类型的值为nil,在你直接使用他的时候,会触发运行时错误。所以使用隐式解析可选类型一定要确保这个量一旦被赋予有效值之后,就会一直具有有效值。

你也可以像使用一个一般可选类型一样来使用一个隐式解析可选类型,比如判断他是否包含有效值:

if assumedString != nil {
    print(assumedString)
}

// 执行结果:An implicitly unwrapped optional string

或者对其使用可选绑定:

if let definiteString = assumedString {
    print(definiteString)
}

// 执行结果:An implicitly unwrapped optional string

可选链

可选链是一种用于查询或调用一个可能不包含有效值的可选类型的属性、方法和下标的过程。如果这个可选类型包含有效值,这个查询或调用过程正常执行;如果这个可选类型不包含有效值,这个查询或调用过程返回nil,表示过程失败。多个查询可以链接在一起,当其中任何一个查询失败时,整个查询链即告失败,整体返回nil。

注意:
Swift中的可选链类似于在OC中向nil发送消息,不同的是,可选链适用于任何类型而且可以被判断是否执行成功。

可选链是强制解析之外的另一种选择

当需要查询或调用一个包含有效值的可选类型的属性或者方法时,通过在其后面加上 ? 号来形成可选链。这和在其后加上 ! 来强制解析其有效值的过程非常相似。主要区别在于,如果这个可选不包含有效值,可选链仅仅会返回nil,表示查询或者调用失败,而强制解析会触发运行时错误,导致程序崩溃。

因为可选链查询或调用成功会返回对应的返回值,失败则返回nil,所以可选链的返回值是一个可选类型,不论所要查询或者调用的属性和方法的返回值是不是可选类型。你可以使用这个返回的可选类型来判断可选链是否执行成功。

具体而言,可选链调用的返回值的类型和其调用的属性的类型或者方法的返回值的类型是相同的,只是这个值被封装在了一个可选类型中。如果用可选链去查询一个 Int 类型的属性,查询成功时,这个可选链的返回值类型为 Int? 。

下面的几段代码演示了可选链和强制解析的区别以及如何判断可选链是否成功。

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

Residence 类型的对象包含一个 Int 类型的属性 numberOfRooms,默认值为1。Person 类型的对象包含一个可选类型的属性 residence,类型是 Residence?。

如果你创建一个 Person 类型的实例,他的 residence 属性默认被初始化为 nil。如下代码所示:

// 创建一个 Person 实例 john,此时 john.residence = nil
let john = Person()

此时如果你想要通过强制解析来使用 john 的 residence 的有效值,会触发运行时错误:

let roomCount = john.residence!.numberOfRooms

// 触发运行时错误,程序崩溃

当 john.residence 包含有效值的时候,上面的代码会执行成功,roomCount 会被正确赋值。但是,当你使用强制解析来获取一个可选类型的有效值时,如果这个可选类型不包含有效值,则一定会触发运行时错误。如上所示。

可选链是获取 numberOfRooms 的值的另一种方法。在可选类型后面加上 ? 即可使用可选链,如下所示:

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

// 执行结果:Unable to retrieve the number of rooms.

上面代码中的可选链告诉 Swift 去将对 residence 是否包含可选值的判断和 numberOfRooms 属性的值的获取链接在一起,并且只有当 residence 包含有效值的时候才去获取 numberOfRooms 属性。

因为获取 numberOfRooms 属性有可能失败,所以整个可选链的返回值是 Int? 。如果 residence 不包含有效值,可选链返回nil,表示无法获取 numberOfRooms 的值。需要注意的是,尽管 numberOfRooms 属性是 Int 类型,获取他的值的可选链的返回值还是一个 Int? 类型。可选链的返回值永远是可选类型。

你可以给 john.residence 属性赋一个值,使他不再为 nil:

john.residence = Residence()

john.residence 现在包含一个有效值。如果此时使用上段代码中的可选链获取 numberOfRooms 属性的值的话,可选链现在会返回一个包含有效值1的 Int 可选类型。

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

// 执行结果:John's residence has 1 room(s).

可选链可以多层链接,查询或调用深层次的属性和方法

可以使用可选链查询更深层次的属性、方法或者下标。下面定义了几个类型,用于演示可选链的多种用法。

Person 类和之前的定义相同:

class Person {
    var residence: Residence?
}

Residence 类添加了更多的属性和方法,其中用到的 Room 类型和 Address 类型会在后面定义:

class Residence {
    var rooms = [Room]()

    // 计算型属性,仅仅是返回 rooms 数组的长度。
    var numberOfRooms: Int {
        return rooms.count
    }

    // 下标方法,简化对 rooms 数组的访问。使用时需提供对应index。
    subscript(i: Int) -> Room {
        get {
            return rooms[i]
        }

        set {
            rooms[i] = newValue
        }
    }

    func printNumberOfRooms() {
        print("The number of rooms if \(numberOfRooms)")
    }

    var address: Address?
}

class Room {
    let name: String

    init(name: String) {
        self.name = name
    }
}

class Address {
    var buildingName: String?

    var buildingNumber: String?

    var street: String?

    // 返回地址
    func buildingIdentifier() -> String? {
        if buildingName != nil {
            // 如果建筑名字不为nil,则返回建筑名字
            return buildingName
        } else if buildingNumber != nil && street != nil {
            // 如果建筑门牌号和街道名字都不为nil,则将他们拼在一起作为地址
            return "\(buildingNumber) \(street)"
        } else {
            // 无法正确的描述地址,返回nil
            return nil
        }
    }
}

通过可选链访问属性

创建一个 Person 实例,并访问他的 numberOfRooms 属性,和之前代码一样:

let john = Person()

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

// 执行结果:Unable to retrieve the number of rooms.

因为 john.residence 为nil,这个可选链返回nil。

你也可以通过可选链给属性赋值:

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress

上段代码中的给 john.residence 的 address 属性赋值的操作将会失败,因为 john.residence 为nil。

通过可选链调用方法

你可以使用可选链调用可选类型属性的方法并且验证改方法调用是否成功。不论这个方法是否具有返回值,或者返回值是什么类型,你都可以使用可选链调用他并且验证他是否调用成功。

Residence 类中的 printNumberOfRooms() 方法输出了 numberOfRooms 的值,下面是这个方法的定义:

func printNumberOfRooms() {
    print("The number of rooms is \(numberOfRooms)")
}

这个方法没有指定返回值。在Swift 中,没有指定返回值的方法或函数都隐性的返回一个 Void 类型,表示他们返回一个(),或者叫空元组。

如果你通过一个可选链来调用这个方法,这个可选链的返回值将是 Void?,而不是 Void,因为可选链的返回类型总是可选类型。这允许我们使用 if 语句来判断是否可以调用 printNumberOfRooms 方法,尽管这个方法没有返回值。如下所示:

if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
} else {
    print("It was not possible to print the number of rooms.")
}

// 执行结果:It was not possible to print the number of rooms.

同样的,通过可选链给可选类型属性的属性赋值时,也可以判断赋值是否成功,可选链在此种情况下的返回值也是 Void? 类型。

if (john.residence?.address = someAddress) != nil {
    print("It was possible to set the address")
} else {
    print("It was not possible to set the address")
}

// 执行结果:It was not possible to set the address

通过可选链访问下标

可以通过可选链访问一个可选类型的下标并验证是否成功。

注意:
当你通过可选链访问一个可选类型下标时,将 ? 放在中括号的前面而不是后面。可选链中的 ? 号总是紧跟在可选类型之后。

下面的代码想要使用可选链,通过下标访问 john.residence 属性中的 rooms 数组的第一个元素。由于 john.residence 目前没有有效值,所以这次下表访问失败了:

if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}

// 执行结果:Unable to retrieve the first room name.

类似的,也可以使用可选链通过下标赋值:

john.residence?[0] = Room(name: "Bathroom")

上面代码中的赋值操作也是失败的,因为 residence 现在没有有效值。

如果你给 john.residence 赋一个有效值,你就可以通过可选链成功地使用下标访问 rooms 数组了。

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("The first room name is \(firstRoomName).")
} else {
    print("Unable to retrieve the first room name.")
}

// 执行结果:The first room name is Living Room.

访问返回可选类型的下标

如果一个下标返回可选类型(比如 Swift 中的 Dictionary 类型),在下标的中括号的后面加上 ? 来使用可选链访问其返回值的属性或方法。

var testScores = ["Dave": [86,82,84],"Bev": [79,94,81]]
// 前两句代码执行成功,因此下标的返回值具有有效值
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0]++
// 执行失败,因为下标的返回值不具有有效值
testScores["Brain"]?[0] = 72

// 执行完毕后,"Dave" 数组为 [91,82,84],"Bev" 数组为 [80,94,91]

使用多层可选链

你可以将多个可选链链接在一起来访问更深层次的属性或方法,但是不管你链接了多少层,整个可选链的返回值的类型还是一个可选类型,并且是可能包含和最终要访问的属性的类型或者方法的返回值的类型相同的有效值的可选类型。多层链接中只要有一层返回nil,则整个可选链失败,返回nil。

if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).")
} else {
    print("Unable to retrieve the address.")
}

// 执行结果:Unable to retrieve the address.

john.residence 包含有效值,但是 john.residence.address 是一个nil,所以上述执行还是失败了。

上述代码中,多层可选链最终要访问的属性的类型是 String?,所以整个可选链的返回类型也是 String?。

如果我们给 address 属性赋一个有效值,就可以成功访问了。

let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
// 赋值成功,此时 john.residence 包含有效值
john.residence?.address = johnsAddress

if let johnsStreet = john.residence?.address?.street {
    print("John's street name is \(johnsStreet).")
} else {
    print("Unable to retrieve the address.")
}

// 执行结果:John's street name is Laurel Street.

链接返回值为可选类型的方法

可以使用可选链调用返回值为可选类型的方法,并且继续链接这个返回值如果需要的话。

下例演示了使用可选链调用 Address 类中的 buildingIdentifier() 方法。这个方法的返回值为 String?,和之前讲的一样,整个可选链的返回值将是 String?。

if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
    print("John's building identifier is \(buildingIdentifier).")
}

// 执行结果:John's building identifier is The Larches.

如果你需要将这个返回值也加入到可选链中来,可以在方法调用的后面加上 ?:

if let beginsWithThe = john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
    if beginsWithThe {
        print("John's building identifier begins with \"The\".")
    } else {
        print("John's building identifier does not begin with \"The\".")
    }
}

// 执行结果:John's building identifier begins with "The".

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。