swift 泛型


/**

 // 泛型

 接受其它函数作为参数的函数有时被称为高阶函数。

 Swift 标准库 中作用于数组的高阶函数中漫游。Swift 泛型,展示如复杂计算运用于数组

 

 */

 

 

 /*

 顶层函数和扩展

 

 写一个函数,它接受一个给定的整型数组,通过计算得到并返回一个新数组,

 数组各项为原数组中对应的整型数据加一。这一切,仅仅只需要使用一个 for 循环就能非常容 易地实现

 */


func incrementArray(xs:[Int]) -> [Int] {

    var result: [Int] = []

    for x in xs {

        result.append(x + 1) }

    return result

}


/**

 

 */

func doubleArray1(xs:[Int]) -> [Int] {

    var result: [Int] = []

    for x in xs {

        result.append(x * 2) }

    return result

}


var tmpArray = doubleArray1([1,2,3,4])


/// 两个函数有大量相同的代码,我们能不能将没有区别的地方抽象出来,并单独写一个体现这

// 种模式且更通用的函数




func computeIntArray(xs: [Int], transform: Int -> Int ) -> [Int] {

    var result: [Int] = []

    

    for x in xs {

        result.append(transform(x))

    }

    return result

}




/**

 *  现在,取决于我们想如何根据原数组得到一个新数组,我们可以向函数传递不同的参数。

 doubleArray 函数和 incrementArray 函数都精简为了一行调用 computeIntArray 的语句:

 */


func doubleArray2(xs:[Int]) -> [Int] {

    return computeIntArray(xs) {

        x in x * 2

    }

}




func computeBoolArray(xs: [Int], transform: Int -> Bool) -> [Bool] {

    var result: [Bool] = []

    for x in xs {

        result . append(transform(x))

    }

    return result

}


func isEvenArray(xs: [Int ]) -> [Bool] {

    return  computeBoolArray(xs) {  x in x % 2 == 0}

}


/**

 *  这个方案的扩展性并不好。如果接下来需要计算 String 类型呢?

 是否还需要定义另 一个高阶函数来接受 Int -> String 类型的参数

 

 解决方案:使用泛型

 genericComputeArray<T> 理解为一个函数族,类型参数 T 的每个选择都会确定一个新函数

 该函数接受一个整型数组和一个 Int -> T类型的函数作为参数,并返回一个[T]类型的数组

 */

func genericComputeArray<T>(xs: [Int], transform: Int -> T) -> [T] {

    var result: [T] = []

    for x in xs {

        result.append(transform(x))

    }

    return result

}


/**

 进一步将这个函数一般化。没有理由让它仅能对类型为 [Int] 的输入数组进行处理

 将数组类型进行抽象,能得到下面这样的类型签名

 

 写了一个 map 函数,它在两个维度都是通用的:对于任何 Element 的数组和 transform: Element -> T 函数,它都会生成一个 T 的新数组。

 这个 map 函数甚至比我们之前 看到的 genericComputeArray 函数更通用。

 

 */

func map<Element,T>(xs:[Element],transform:Element ->T)->[T]{

    var result :[T] = []

    for x in xs{

        result.append(transform(x))

    }

    return result

}


/**

 *   事实上,可以通过 map 来定义 genericComputeArray:

 */

func genericComputeArray2<T>(xs: [Int], transform: Int -> T) -> [T] {

    return map(xs, transform: transform)

}


// 按照 Swift 的惯例将 map 定义为 Array 的扩展会更合

extension Array {

    func map<T>(transform: Element -> T) -> [T] {

        var result: [T] = []

        for x in self {

            result . append(transform(x)) }

        return result

    }

}


/**

 map(xs, transform) 的替代,我们现在可以通过 xs.map(transform) 来调用 Arraymap 函数

 

 定义 map 函数,它已经是 Swift 标准库的 一部分了(实际上,它基于 SequenceType 协议被定义)

 map 的定义中并 没有什么复杂难懂的魔法 ,能够轻松地自己定义它

 */


func genericComputeArray_<T>(xs: [Int], transform: Int -> T) -> [T] {

    

    return xs.map(transform)

}


var mapArray  = genericComputeArray_(tmpArray) {

    x in x

}





// Filter

let exampleFiles = ["README.md", "HelloWorld.swift", "FlappyBird.swift"]


func getSwiftFiles( files: [String]) -> [String] {

    var result: [String] = []

    for  file in  files {

        if  file .hasSuffix(".md") {

            result . append(file)

        }

    }

    return result

}

getSwiftFiles(exampleFiles)



// MARK: - 想查找没有扩展名的所有文 ,或者是名字以字符串 "Hello" 开头的文件

// 为了进行一个这样的查找,我们可以定义一个名为  filter 的通用型函数。就像之前看到的 map 那样,  lter 函数接受一个函数作为参数。  filter 函数的类型是 Element -> Bool —— 对于数 组中的所有元素,此函数都会判定它是否应该被包含在结果中

// 就像 map 一样,Swift 标准库中的数组类型已经有定义好的filter 函数了。所以除非是作为练

//,否则并没有必要重写它


extension Array {

    func   filter (includeElement: Element -> Bool) -> [Element] {

        var result: [Element] = []

        for x in self where includeElement(x) {

            result . append(x)

        }

        return result

    }

}


func getSwiftFiles2( files: [String]) -> [String] {

    

    return  files.filter {

        file in  file .hasSuffix(".swift")

    }

}


getSwiftFiles2(exampleFiles)




// Reduce

/**

下面函数有什么共同:

它们都将变量 result 初始化为某个值。随后对输入数组 xs 的每一项 进行遍历,最后以某种方式更新结果。


*/

func sum(xs: [Int]) -> Int {

    var result: Int = 0

    for x in xs {

        result += x

    }

    return result

}


func product(xs:[Int]) -> Int {

    var result: Int = 1

    for x in xs {

        result = x * result

    }

    return result

}


/**

 想要连接数组中的所有字符串

 

 */

func concatenate(xs: [String]) -> String {

    var result: String = ""

    for x in xs {

        result += x

    }

    return result

}

func prettyPrintArray(xs: [String]) -> String {

    var result: String = "Entries in the array xs:\n"

    for x in xs {

        result = " " + result + x + "\n"

    }

    return result

}



/**

 *  为了定义一个可以体现所需类型的泛型函数,需要 对两份信息进行抽象:赋给 result 变量的初始值,和用于在每一次循环中更新 result 的函数

 

 这个函数的泛型体现在两个方面:对于任意 [Element] 类型的输入数组来说,它会计算一个类 型为 T 的返回值。这么做的前提是,首先需要一个 T 类型的初始值 (赋给 result 变量),以及一 个用于更新 for 循环中变量值的函数 combine: (T, Element) -> T。在一些像 OCaml Haskell 一样的函数式语言中,reduce 函数被称为 fold fold_left

 */

extension Array {

    func reduce<T>(initial: T, combine: (T, Element) -> T) -> T {

        var result = initial

        for x in self {

            result = combine(result, x)

        }

        return result

    }

}


// reduce 来定义上面的函数

func sumUsingReduce(xs: [Int]) -> Int {

    return xs.reduce(0) { result, x in result + x }

}


// 除了写一个闭包,也可以将运算符作为最后一个参数,这使得代码更短

//自定义 reduce 仅仅只是为了练习,Swift 的标准库已经为数组提供了 reduce 函数

func productUsingReduce(xs: [Int]) -> Int {

    return xs.reduce(1, combine: *)

}

func concatUsingReduce(xs: [String]) -> String {

    return xs.reduce("", combine: +)

}



/**

 假设有一个数组,它的每一项都是数组, 我们想将它展开为一个单一数组。

 可以使用 for 循环编写一个函数

 

 */

func atten<T>(xss: [[T]]) -> [T] {

    var result: [T] = []

    for xs in xss {

        result += xs

    }

    return result

}


// 然而,若使用 reduce 则可以像下面这样编写这个函数

func  attenUsingReduce<T>(xss: [[T]]) -> [T] {

    return xss.reduce([]) { result, xs in result + xs }

}


//实际上,我们甚至可以使用 reduce 重新定义 map   filter

extension Array {

    func mapUsingReduce<T>(transform: Element -> T) -> [T] {

        return reduce([]) {

            result, x in return result + [transform(x)]

        }

    }

    func  filterUsingReduce(includeElement: Element -> Bool) -> [Element] { return reduce([]) {

        result, x in return includeElement(x) ? result + [x]:result

        }

    }

}



// 实际运用

struct City {

    let name: String

    let population: Int

}


let paris = City(name: "Paris", population: 2241)

let madrid = City(name: "Madrid", population: 3165)

let amsterdam = City(name: "Amsterdam", population: 827)

let berlin = City(name: "Berlin", population: 3562)

let cities = [paris, madrid, amsterdam, berlin]


// 想筛选出居⺠数量至少一百万的城市,并打印一份这些城市的名字及总人口数的

//列表。我们可以定义一个辅助函数来换算居⺠数量

extension City {

    func cityByScalingPopulation() -> City {

        return City(name: name, population: population * 1000)

    }

}


/**

首先将居⺠数量少于一百万的城市过滤掉。

然后将剩下的结果通过 cityByScalingPopulation 函数进行 map 操作。

最后,使用 reduce 函数来构建一个包含城市 名字和人口数量列表的 String

这里使用了 Swift 标准库中 Array 类型的 mapfilter reduce 定义。

于是,可以顺利地链式使用过滤和映射的结果。表达式 cities .  filter (..) 的结果是一个数组,

对其调用 map;然后这个返回值调用 reduce 即可得到最终结果

*/


cities .filter { $0.population > 1000 }

    .map { $0.cityByScalingPopulation() }

    .reduce("City: Population") {

        result, c in

        return result + "\n" + "\(c.name): \(c.population)"

}




/**

 *

 泛型和 Any 类型

 

 Swift 还支持 Any 类型,它能代表任何类型的值。从表面上看,这好像和泛型极其

 相似。Any 类型和泛型两者都能用于定义接受两个不同类型参数的函数。然而,理解两者之间 的区别至关重要:泛型可以用于定义灵活的函数,类型检查仍然由编译器负责; Any 类型则 可以避开 Swift 的类型系统 (所以应该尽可能避免使用)

 */

 

 //构想一个函数,除了返回它的参数,其它什么也不做。如果使

 //用泛型,我们可能写为下面这样:

 

 

 /**

 noOp noOpAny 两者都将接受任意参数。关键的区别在于我们所知道的返回值。在 noOp 定义中,我们可以清楚地看到返回值和输入值完全一样。而 noOpAny 的例子则不太一样,返回 值是任意类型甚至可以是和原来的输入值不同的类型。

 */

func noOp<T>(x: T) -> T {

    return x

}


//而使用 Any 类型,则可能写为这样:

func noOpAny(x: Any) -> Any {

    return x

}


//给出一个 noOpAny 的错误 定义

//使用 Any 类型可以避开 Swift 的类型系统。然而,尝试将使用泛型定义的 noOp 函数返回值设 0 将会导致类型错误

func noOpAnyWrong(x: Any) -> Any {

    return 0

}


/**

我们需要得到的是一个 A -> C 类型的函数。由于我们并不知道其它任何有关 C 的信息,所以暂 时没有能够返回的值。如果知道 C 是像 Int 或者 Bool 这样的具体类型的话,我们就可以返回一 个该类型的值,例如分别返回 5 True。然而函数必须能处理任意类型的 C,所以我们不能轻率地返回具体值。在 >>> 运算符的参数中,只有 g: B -> C 函数提及了类型 C。因此, B 类型 的值传递给函数 g 是我们能够触及类型 C 的唯一途径。

同样,要得到一个 B 类型值的唯一方法是将类型为 A 的值传递给 f。类型为 A 的值唯一出现的 地方是在我们运算符要求返回的函数的输入参数里。因此,函数组合的定义只有这唯一一种可 ,才能满足所要求的泛型类型。

*/

infix  operator >>> { associativity left }

func >>> <A, B, C>(f: A -> B, g: B -> C) -> A -> C {

    return { x in g(f(x))

    }

}


//可以用相同的方式定义一个泛型函数,该函数能够将任意的接受两个元素的元组作为输入 的函数进行柯里化 (curry) 处理,从而生成相应的柯里化版本

func curry<A,B,C>(f: (A,B)->C)->A->B->C{

    return { x in { y in f(x, y)}

    }

}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Swift 中,泛型的 `where` 语句用于限制泛型类型。它可以在定义泛型函数或类型时使用。语法如下: ``` where 泛型别名 : 限制条件 ``` 例如: ``` func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil } ``` 在上面的例子中,泛型别名为T,限制条件为T: Equatable,意思是T必须符合Equatable协议 还可以指定多个限制条件 ``` func test<T>(_ value: T) where T: Equatable, T: Hashable { } ``` 这里的限制条件为T: Equatable, T: Hashable,意思是T必须符合Equatable和Hashable协议 ### 回答2: 在Swift中,泛型的where语句用于对泛型进行条件限制,以满足特定需求。使用where语句可以对泛型类型进行约束,使其满足特定的类型要求。 在泛型函数中,我们可以使用where语句来限制泛型参数的类型。例如,我们可以声明一个泛型函数,其中泛型参数必须遵循某个协议或满足某种特定的条件。下面是一个示例: ``` func process<T>(data: T) where T: Equatable { // 在这里操作泛型参数data,比如进行相等比较等操作 } ``` 在上面的示例中,我们限制了泛型参数T必须遵循Equatable协议,即具有相等比较能力。这样,在函数内部就可以使用相等比较操作符进行操作。 除了在泛型函数中使用where语句外,也可以在泛型类型和协议声明中使用where语句对泛型参数进行进一步的限制。例如: ``` protocol Container { associatedtype Item func addItem(item: Item) } struct MyContainer<T>: Container where T: Equatable { typealias Item = T func addItem(item: Item) { // 在这里添加item到容器中 } } ``` 在上面的示例中,我们定义了一个Container协议,其中关联类型Item表示容器中的元素类型。然后,我们通过where语句限制了泛型参数T必须满足Equatable协议,以确保容器中的元素可以进行相等比较。 总结来说,在Swift中,泛型的where语句可以用于泛型函数、泛型类型和协议的声明中,用于对泛型参数进行类型约束和条件限制,以满足特定需求。 ### 回答3: 在Swift中,泛型的where语句用于为泛型类型或泛型函数添加额外的约束。它允许我们在使用泛型时对其类型参数进行更详细的限制。 泛型的where语句可以使用在两个地方:泛型函数和泛型类型。 对于泛型函数,我们可以使用where语句来添加类型约束。例如,我们可以声明一个泛型函数来交换两个变量的值: func swap<T>(a: inout T, b: inout T) where T: Equatable { if a == b { return } let temp = a a = b b = temp } 在上面的代码中,我们使用了where语句来添加了一个类型约束,即T必须遵循Equatable协议。这意味着只有那些可比较相等的类型才能调用这个函数。 对于泛型类型,我们可以使用where语句来添加更多的类型约束。例如,我们可以声明一个泛型结构体,它的关联类型必须遵循特定协议: struct Container<T> where T: CustomStringConvertible { var items: [T] func printItems() { for item in items { print(item.description) } } } 在上面的代码中,我们使用了where语句来添加了一个类型约束,即关联类型T必须遵循CustomStringConvertible协议。这样,我们就可以在printItems方法中使用item的description属性。 总之,泛型的where语句在Swift中用于为泛型类型或泛型函数添加额外的约束。通过使用where语句,我们可以对类型参数进行更详细的限制,以满足特定的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值