你对Swift中的元组了解多少呢?
...
很有自信嘛
...
看完这篇文章再说喽
元组
- 元组是Swift中特有的,OC中并没有相关数据类型
- 元组是一种数据结构,它可以把多个值,组成一个复合值,元组内元素的类型无需相同
元组的定义格式:
let 元组名称 = (元素,元素...)
数组?字典?元组!
- 使用数组定义的数据
缺点:在一个数组中,如果存在多种数据类型,所有的元素类型都将会一并变为NSObject
例:
let infoArray = ["lyu" , 18]
let name = infoArray[0] //缺点:name的类型是NSObject,而不是String,也就是说我们是没有办法敲出name.characters这个方法的
let length = name.characters.count //编译报错
- 使用字典定义的数据
缺点:在一个字典中,如果其value值存在多种数据类型,所有的value类型都将会一并变为NSObject
例:
let infoDic = ["name" : "lyu" , "age" : 18]
let name = infoDic["name"] //缺点:name的类型是NSObject,而不是String,也就是说我们是没有办法敲出name.characters这个方法的
let length = name.characters.count //编译报错
- 使用元组来定义数据:
优点:元组中的数据是按照他们的真实类型来存储的
例:
let infoTuple = ("lyu" , 18) //元组会为他的元素储存其真实类型
let name = infoTuple.0 //name的类型为String
let length = name.characters.count //毫无压力的拿到字符串的长度
元组的使用方法
- 给元组中的元素起别名
例:
let errorTuple = (newName : "Not Found" , newCode : 404)
let errorName = errorTuple.newName
let errorCode = errorTuple.newCode
//当然.0和.1仍然可以取值
let errorName1 = errorTuple.0
let errorCode1 = errorTuple.1
- 给元组起别名的另一种方法:
要注意的是,通过这种方法来创建元组是拿不到元组名字的
缺点:拿不到元组的名字
优点:快速解构
例:
let (newName , newCode) = ("Not Found" , 404)
let errorName = newName
let errorCode = newCode
提示:这种方法来创建的元组相当于直接创建了两个常量
元组的进阶使用方法
- 与Switch搭配进行复杂条件的判断:
例:招聘一个20岁以下的员工,并同时打印其个人信息
let name = "lyu" //姓名
let age = 18 //年龄
var personalInfo = [String : NSObject]() //个人信息
personalInfo["height"] = 1.80 //个人信息
switch (age,name,personalInfo) { //包装元组,元组中元素的命名要与姓名,年龄,个人信息完全一致
case (let age , let name , let personalInfo) where age < 20: //满足age<20则执行case
print(age)
print(name)
print(personalInfo)
default:
print(age)
}
- 作为函数的返回值,来创建多个返回值的函数
例:计算一个数组中奇数偶数的值,一并返回
func getCount(nums : [Int]) -> (Int , Int) { //将返回值构建为一个元组
var oddCount = 0 //初始化偶数个数
var evenCount = 0 //初始化奇数个数
for num in nums { //遍历数组
if num % 2 == 0 { 判断是否为偶数
oddCount += 1
}
else //反之为奇数
{
evenCount += 1
}
}
return (oddCount , evenCount) 返回元组:(偶数,奇数)
}
let nums = [12,14,15,2,77,13]
let counts = getCount(nums)
print(counts)
print(counts.0)
print(counts.1)
- 函数作为元组的元素,进行多函数同时调用
例:
func test1() -> String{
return "test1"
}
func test2() -> String{
return "test2"
}
func test3() -> String{
return "test3"
}
let funcTuple = (a : test1() , b : test2() , c : test3())
print(funcTuple)
-
交换值
被交换的必须是变量,并且这两个变量类型必须相同
例:
var (x , y) = (11 , 22)
(x , y) = (y , x)
print(x , y)
元组的超进阶使用方法
- 以假乱真:使用元组代替结构体
例:
//定义结构体
struct newS {
var name : String
var age : Int
}
let temp = newS(name : "lyu" , age :18)
//定义元组
let tuple = (name : "lyu" , age : 18)
//使用元组和结构体
print(tuple.name)
print(temp.name)
Tips:结构体?元组?
我们发现这两个家伙还是有所不同的:元组并没有结构体的声明部分,所以如果只是临时使用,或临时拼凑一个结构体,那么建议使用元组
如果你的需求超出了"临时"(根据你的代码自己判断喽~)的范围,那么还是建议将数据封装成结构体
另外:也可以使用元组来代替"匿名结构体哦"
- 处理数据的过程中,将某一个函数的返回值作为临数据传入另一方法中
- 元组可以作为函数的参数
- 元组也可以作为函数的返回值,既然如此,这种用法当然也可以成立了
//元组作为函数返回值
func getViewInfo() -> (r : Int , alpha : Double , location : (Double , Double)){
return (255 , 0.5 , (100 , 100))
}
//元组作为函数参数
func getAlpha(tuple : (r : Int , alpha : Double , location : (Double , Double))) -> Double{
return tuple.alpha
}
let alpha = getAlpha(getViewInfo())
print(alpha)
- 当然根据上一条使用方法,我们也可以想到本例也可以使用结构体来实现,如下:
//声明结构体
struct Location {
var x : Double
var y : Double
}
struct Info {
var r : Int
var alpha : Double
var location : Location
}
//定义函数
func getViewInfo() -> (Info){
return Info(r: 255 , alpha: 0.5 , location: Location(x: 100 , y: 100))
}
func getAlpha(stc : Info) -> Double{
return stc.alpha
}
//调用函数
let alpha = getAlpha(getViewInfo())
print(alpha)
tips:
为了两个函数而刻意定义两个结构体,这种做法显然太浪费了,所以这里才为大家介绍了上面元组代替结构体的方法
- 具体定义元组类型
//typealias相当于C/OC中的typedef,用于起别名
typealias Tuple = (name : String , age : Int ,height : Double) //这与结构体的声明及其相似
func printTuple(tempTuple : Tuple){ //使用Tuple类型定义形参
print(tempTuple)
}
//下面提供三种用法
printTuple((name: "lyu" , age : 18 , height : 1.80))
printTuple(Tuple("lyu" , 18 , 1.80))
printTuple(("lyu" , 18 , 1.80))
- 约束一个类型元素的个数
当我们创建一个数组可变数组,并且希望这个数组未来存储7组数据,例如统计一周内的每日降雨量
//做法1:我们首先想到使用一个数组来包装这7天的数据
var info = [Int]()
info.append(11)
//缺点:这种做法没办法控制数组中元素的数量,如果外界添加元素的时候不小心添加了8个,就没办法按地球的逻辑解释了,难道真的有星期八~
//做法2:使用元组包装数据
var info : (Int,Int,Int,Int,Int,Int,Int,Int) //什么?不是7个,一定是你撸多眼花了
//优点:这样做可以把info中的元素个数约束为7个,多于少于7都会报错
- 作为函数的可变参数
当函数的参数数量不确定的时候
例:
func sum(numbers : Int...) -> Int{
return numbers.reduce(0, combine: +) //第一个参数为基值,代表在0的基础上累加
}
let result = sum(1,2,3)
- 元组与泛型
元组中元素的真实类型是根据元组中元素类型来确定的,所以与其让泛型来约束元组,还不如根据我们的需求来定义一个明确数据类型的元组,反过来控制泛型- 由元组的类型来指定函数的泛型
//例:元组与泛型与函数
func three<c1 , c2 , c3>(tuple : (c1 , c2 , c3)) -> c3{ //利用泛型来声明元组属性类型,此时元组的属性类型与泛型都还是不确定的
return tuple.2
}
//随便传入一个元组,均可成功调用该函数
let height = three(("Lyu" , 18 , 1.88)) //调用three函数的那一时刻,Swift根据参数(元组)类型推导出three的泛型!此时拿到的height是明确的Double类型
- 根据需求,由子类来指定父类泛型
例:元组与泛型与类
class superClass<c1 , c2 , c3>{ //定义父类,此时泛型不确定
typealias numbers = (c1 , c2 , c3) //利用此时不确定的泛型来声明一个元组
func printNewNumbers(nums : numbers) -> Void {
print(nums)
}
}
class childClass<c1 , c2 , c3> : superClass<c1 , c2 , c3> { //定义子类,此时父类的泛型与子类相同,但子类的泛型不确定
}
let child = childClass<String , Int , Double>() //实例化对象,我们可以在此处根据需求来确定泛型,此时父类与子类泛型均以确定,
child.printNewNumbers(("lyu" , 18 , 1.80)) //创建元组作为参数
//当然我们也可以这样写
class superClass<c1 , c2 , c3>{
typealias numbers = (c1 , c2 , c3)
func printNewNumbers(nums : numbers) -> Void {
print(nums)
}
}
class childClass<c1 , c2> : superClass<c1 , c2 , Double> { //在此处确定元组中某一个元素的类型(当然,前提你真的确定这个元素的类型...)
}
let child = childClass<String , Int>() //这时,我们只需要确定前两个元素的类型即可
child.printNewNumbers(("lyu" , 18 , 1.80))
tips:
当我们需要封装一个函数,但却不明确要传入的参数(不只是元组),可以利用这种思想,举一个最简单的例子如下:
func myNameOrAge<c1>(nameOrAge : c1) -> c1{
return nameOrAge
}
let name = myNameOrAge("Lyu") //这里name的类型是String而不是可选类型,也不是anyObject
let age = myNameOrAge(18) //这里age的类型是Int而不是可选类型,也不是anyObject
也就是说:此时反过来看return nameOrAge这一句中已经拿到了nameOrAge的真是类型,假如我们在函数体内做一些复杂的运算,最终返回的值仍然是一个已知的类型,是不是比anyObject要好的多呢
- 元组作为函数的参数
- 利用有参元组,作为带外部参数函数的参数
func sum(a a : Int , b : Int , hello : String) -> Int {
return a + b
}
let tuple = (a : 1,b : 2, hello : "hello") //利用有参元组作为带外部参数的函数的参数
let result = sum(tuple)
- 利用无参元组,作为不带外部参数函数的参数
func sum(a : Int , _ b : Int , _ hello : String) -> Int {
return a + b
}
let tuple = (1 , 2 , "hello") //利用无参元组作为不带外部参数函数的参数
let result = sum(tuple)
- 一个函数返回的元组作为另一个函数的参数
func getTuple() -> (Int , Int , String){
return(1, 2, "hello")
}
func printTuple(tuple : (Int , Int , String)){
print(tuple)
}
printTuple(getTuple())
//这种传递方式可以让我们无需结构元组(返回值),即可完成多个数据的传递
网友评论