Swift-31-泛型和类型操作

这篇具有很好参考价值的文章主要介绍了Swift-31-泛型和类型操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

泛型

Swift泛型(generics) 让我们写出的类型和函数可以使用对于我们或编译器都未知的类型。 很多内建类型(包括可空类型、数组和字典)都是用泛型实现的,比如数组和一些集合就是用泛型方式来实现的。

一种运行时进行类型检查的技术,效率高但是不安全。在swift中泛型可用于结构体、类以及函数和方法

定义可空类型的泛型变量

let x: Optional<Int> = 3

print(x) //~~ 3

上述代码实际上用到了系统提供的协议,具体的在后续详细讲解,这里只了解其用法就可以了

enum Optional<Wrapped> {
    case None
    case Some(Wrapped)
}

定义泛型类型

语法:class/struct Name<Type>,上述尖括号中的Type是一个占位符,也可换成其它名称,比如T,在实例化时会换成实际的值。

比如一个简单的堆栈实现

//Element是一个占位符,也可换成其它名称
struct Stack<T>: Sequence { 
    var items = [T]()

    mutating func push(_ newItem: T) {
        items.append(newItem)
    }
    
     mutating func pop() -> T? {
        guard !items.isEmpty else {
            return nil
        }
        return items.removeLast()
    }
}

//~~~使用,在代码运行时,泛型T会换成Int
var stack = Stack<Int>()    

定义泛型函数和方法

函数和类的方法的返回值和参数也可以用泛型来代码,比如下拉代码声明了一个泛型函数。
Swift-31-泛型和类型操作,MacOS,swift,ios,objective-c,macos,开发语言

    func myMap<T,U> ( _ items:[T], _ f:(T)->(U) )  -> [U]{
        var result = [U]()
        for item in items{
            result.append( f(item) )
        }
        return result
    }

方法测试

let string = ["one", "two", "three"]
let stringLen = myMap(string){$0.count} //第一个cod为一个函数
print(stringLen) //~~ [3,3,5]

给泛型占位符设置约束条件

泛型的比较,必须要把泛型标识符声明为系统提供的Equatable类型。

func checkIfEqual<T: Equatable>(_ first: T, _ second: T) -> Bool {
    return first == second
}
print(checkIfEqual(1, 1)) //~~true
print(checkIfEqual("a string", "a string")) //~~true
print(checkIfEqual("a string", "a different string")) //~~false

多个约束符的例子,下例表示用CustomStringConvertible保证了first和second都有返回字符串的属性description。

func checkIfDescriptionsMatch<T: CustomStringConvertible, U: CustomStringConvertible>(
        _ first: T, _ second: U) -> Bool {
    return first.description == second.description
}

print(checkIfDescriptionsMatch(Int(1), UInt(1)))
print(checkIfDescriptionsMatch(1, 1.0))
print(checkIfDescriptionsMatch(Float(1.0), Double(1.0)))

泛型与协议

协议是不可以直接使用泛型的,如果想在协议中使用泛型,可以使用一个叫“关联类型”的特性。用到关键字 associatedtype来修饰协议属性,比如系统提供的IteratorProtocol协议就是如下定义的:

protocol IteratorProtocol {
    associatedtype Element 
    mutating func next() -> Element?
}

上述associatedtype Element表示符合这个协议的类型必须提供具体类型做为Element类型。符合这个协议的类型应该在其定义为内部为Element提供typealias定义,那么就可以按如下方式使用了:

//用 StackIterator 把Stack封装起来。
struct StackIterator<T>: IteratorProtocol {
    typealias Element = T
    
    var stack: Stack<T>
    
    mutating func next() -> Element? {
        return stack.pop()
    }
}

这段代码可以借助Swift类型推断功能,简写为如下形式:

struct StackIterator<T>: IteratorProtocol {
    var stack: Stack<T>

    mutating func next() -> T? {
        return stack.pop()
    }
}

使用

var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
var myStackIterator = StackIterator(stack: myStack)
while let value = myStackIterator.next() {
    print("got \(value)")
}

where子语句

用占位类型s把pushAll(_:)变成泛型方法,它是符合Sequence协议的类型。S的约束保证我们可以用for-in语法循环遍历之。不过,这还不够。为了把从sequence中取出的数据项推入栈,需要确保从序列类型中来的数据项类型和栈元素的类型匹配。也就是说,还需要一个约束让S所产生元素的类型是Element。

    //where语句相当于一个过滤器
    mutating func pushAll<S: Sequence>(_ sequence: S) 
                                       where S.Iterator.Element == Element {
        for item in sequence {
            self.push(item)
        }
    }

附:Stack 示例实现

struct Stack<Element>: Sequence {
    var items = [Element]()

    mutating func push(_ newItem: Element) {
        items.append(newItem)
    }

    mutating func pop() -> Element? {
        guard !items.isEmpty else {
            return nil
        }
        return items.removeLast()
    }

    func map<U>(_ f: (Element) -> U) -> Stack<U> {
        var mappedItems = [U]()
        for item in items {
            mappedItems.append(f(item))
        }
        return Stack<U>(items: mappedItems)
    }

    // Sequence 协议的方法
    func makeIterator() -> StackIterator<Element> {
        return StackIterator(stack: self)
    }

    mutating func pushAll<S: Sequence>(_ sequence: S) where S.Iterator.Element == Element {
        for item in sequence {
            self.push(item)
        }
    }
}

类型操作

值的比较

类型的比较在很多场景下都有需求,在Swift中可通过实现Equatable和Comparable这两个协议来实现。

实现Equatable协议

struct Point: Equatable {
    let x: Int
    let y: Int
    static func == (lhs: Point, rhs: Point) -> Bool {
        return (lhs.x == rhs.x) && (lhs.y == rhs.y)
    }
}
let a = Point(x: 3, y: 4)
let b = Point(x: 3, y: 4)
let abEqual = (a == b) //~~ true
let noAbEqual = (a != b) //~~ false

上述代码中==(中缀运算符)被声明为了static方法,事实上==是定义在全局范围内的。

实现Comparable协议

Comparable会提供更多的功能,因为Comparable继承了Equatable。

//自定义的Point结构体实现Comparable
struct Point: Comparable { //因为继承的原因,所以这块不需要写成Equatable,Comparable 
    let x: Int
    let y: Int
    
    static func ==(lhs: Point, rhs: Point) -> Bool {
        return (lhs.x == rhs.x) && (lhs.y == rhs.y)
    }
    
    static func <(lhs: Point, rhs: Point) -> Bool {
        return (lhs.x < rhs.x) && (lhs.y < rhs.y)
    }
}

let a = Point(x: 3, y: 4)
let b = Point(x: 3, y: 4)

let abEqual = (a == b) //true
let abNotEqual = (a != b) //false

let c = Point(x: 2, y: 6) //false
let d = Point(x: 3, y: 7) //false

let cdEqual = (c == b) //false
let cLessThanD = (c < d) //true

let cLessThanEqualD = (c <= d) //true
let cGreaterThanD = (c > d) //false
let cGreaterThanEqualD = (c >= d) //false

Swift-31-泛型和类型操作,MacOS,swift,ios,objective-c,macos,开发语言

自定义运算符

Swift允许开发者创建自定义运算符。这个特性意味着我们可以创建自己的运算符来表示两个Person的实例结婚了。自定义运算符不太建议使用,因为它也只限于数学运算范围内,正常情况下使用系统提供的就够了。

定义自定义类

class Person: Equatable {
    var name: String
    var age: Int
    weak var spouse: Person?
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    func marry(_ spouse: Person) {
        self.spouse = spouse
        spouse.spouse = self
    }
}

添加自定义运算符

在Person类声明的外面添加以下代码,以添加自定义运算符。

//声明一个新运算符
infix operator +++
func +++(lhs: Person, rhs: Person) {
    lhs.spouse = rhs
    rhs.spouse = lhs
}

添加自定义运算符到默认组

precedencegroup Marriage {
    associativity: none  //这是一个运算优先级定义
}

如果没有上述代码,则因为swift内部对新添加的运算符默认添加到swift内部默认的组为DefaultPrecedence。文章来源地址https://www.toymoban.com/news/detail-860719.html

使用自定义运算符

let drew = Person(name: "Drew", age: 33)
let matt = Person(name: "Matt", age: 32)

到了这里,关于Swift-31-泛型和类型操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Swift/Objective-c】公司项目优化(二) - 下拉刷新抖动问题

    使用MJRefresh进行列表下拉刷新时,会出现列表上下颤抖问题 抖动的原因 我们先来看看在手松开之后我们对scrollView做了什么事情: ScrollViewDidEndDragging  =  setContentInset: 为了保证在“Loading”的状态下,下拉刷新控件可以展示,我们对contentInset做了修改,增加了inset的top. 那这样

    2024年01月20日
    浏览(42)
  • Swift自动布局: SnapKit,相当于Objective-C中的Masonry。

    OC里面,我们常用Masonry,SDAutoLayout。 Swift里,我们常用SnapKit。 一、项目集成 Podfile 导入 使用 #注意# 对于如何使用SnapKit,这里简单讲一些常用的场景: 场景1: 在view中心添加一个长宽200的view 场景2: 在红色view里,添加一个子view,距离顶部30px 场景3: 添加两个view,高宽相等,

    2024年01月17日
    浏览(49)
  • iOS开发Swift-8-类的继承,方法重写,构造器,枚举类型,可选类型,强制解包,可选绑定,隐式可选类型...

    1.类的继承  2.方法的重写 3.构造器: 创建对象;给对象进行初始化  4.枚举类型 5.枚举的原始值 6.枚举的简写  7.可选类型  8.强制解包 9.可选绑定  10.隐式可选类型  11.可选类型自动赋值

    2024年02月09日
    浏览(43)
  • Java中泛型和Object类型 初级进阶教程(一)

    在学习的过程中,常常看到某个类或者接口等中使用 ListT, TestT,其中T的作用是什么呢? 1 在类中使用泛型 2 使用多个泛型 3 在类中使用泛型 4 在方法中使用泛型 5 限制泛型类型 6 通配符 (Wildcard) 总结:泛型和Object类型之间的区别 类型安全: 泛型 T : 泛型提供了编译时类型

    2024年02月01日
    浏览(54)
  • iOS开发Swift-函数

     (1)无参函数 (2)多参函数 (3)无返回值 (4)多重返回值 (5)可选元组返回类型(元组可以是nil) (6)隐式返回的函数 任一可以被写成一行return的函数,return(x) + for。 调用的时候: 方法名(for: 参数) (1)指定参数标签 (2)忽略参数标签 (3)默认参数值 (4)可变参数 一个可变参数可接受0个或多

    2024年02月11日
    浏览(55)
  • IOS-闭包学习-Swift

    闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数(Lambdas)比较相似。 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量。 Swift 会为你管理在捕

    2024年01月24日
    浏览(48)
  • iOS开发Swift-闭包

    将很长的闭包表达式作为最后一个参数传递给函数,不用写出他的参数标签。 嵌套函数可捕获其外部函数所有参数、变量、常量。 当一个闭包作为一个参数传到一个函数中,但闭包在函数返回之后才被执行,则称闭包逃逸。 标注@escaping,表示允许闭包逃逸。  包装传递给函数

    2024年02月11日
    浏览(63)
  • IOS-生命周期-Swift

    App主要有五种状态,分别是: 未运行——Not running 应用程序没启动 未激活——Inactive 程序在前台运行,不过没有接收到事件。 一般每当应用要从一个状态切换到另一个不同的状态时,中途过渡会短暂停留在此状态。唯一在此状态停留时间比较长的情况是:当用户锁屏时,或

    2024年01月23日
    浏览(53)
  • iOS开发Swift-枚举

    枚举:一组相关的值定义了一个共同的类型,使你可以在代码中以类型安全的方式来使用这些值。 原始值:定义枚举时被预先填充的值。 (1)整数为原始值时,隐式赋值递增1。未设置原始值时,默认为0,之后递增1. (2)字符串为原始值,隐式赋值为枚举成员的名称。

    2024年02月11日
    浏览(56)
  • iOS开发Swift-基础部分

    系统可通过赋初始值进行自动推断。 平时可加可不加,同一行中有两句话必须加。 Int           UInt(最好不用) Double 64位 很大/高精度情况下使用 15位小数 Float 32位 对精度要求不高的情况下用 6位小数 十进制数   17 二进制 0b前缀 0b10001 八进制 0o前缀 0o21 十六进制 0x前缀

    2024年02月11日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包