泛型swift
2016-08-30 17:14:02 qq_18674153 阅读数 173

下面是一个泛型的函数

func SwapTwoValues <T> (inout a: T,inout b :T){
    let  tempValue = a
    a = b
    b = tempValue
}
这个函数主体、功能跟上面的例子类似,用来交换两个同样类型的值,但是这个函数用 T 占位符来代替实际的类型。并没有指定具体的类型,但是传入的a ,b 必须是同一类型T。在调用这个函数的时候才能指定 T 是那种具体的类型。还有函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型

SwapTwoValues(&oneInt, b: &twoInt)
print("oneInt:\(oneInt),twoInt:\(twoInt)") // oneInt:3,twoInt:4

var oneStr = "hello"
var twoStr = "world"

SwapTwoValues(&oneStr, b: &twoStr)
print("oneStr:\(oneStr),twoStr:\(twoStr)")// oneStr:world,twoStr:hello

var oneDouble = 10.01
var twoDouble = 20.02
SwapTwoValues(&oneDouble, b: &twoDouble)
print("oneDouble:\(oneDouble),twoDouble:\(twoDouble)")// oneDouble:20.02,twoDouble:10.01




2016-03-06 20:14:00 weixin_33994444 阅读数 3

泛型是为Swift编程灵活性的一种语法,在函数、枚举、结构体、类中都得到充分的应用,它的引入可以起到占位符的作用,当类型暂时不确定的,只有等到调用函数时才能确定具体类型的时候可以引入泛型。

泛型函数

定义

fun 函数名<T,S>(形参列表)->返回值类型
{
     //函数体...
}

例子:

 func copyArray<T>(src:[T],inout dest:[T]) {
    for element in src
    {
     dest.append(element)
    }

     var arr=[1,2]
    copyArray([3,4], dest: &arr)
    print(arr)  

在这里我们运用泛型为函数提供了一个T类型的占位符,这个占位符就可以在函数的实际调用中被替换成真是类型。

结构体泛型

 struct WXRect<T>
{
    var x:T
    var y:T
    var Add:(T,T)
        {
        return (self.x,self.y)
        }
 }
     let rect=WXRect<Double>(x: 20.0, y: 20.0)
    let (30.0,20.0)=rect.Add
    print("(\(x),\(y))")

类中泛型

    class Swift<T> {
    var info:T
    init(info:T)
   {
    self.info=info
    }
}

    var swift=Swift<String>(info:"Swift泛型")
    print("\(swift.info)真强大") 

类型约束

上面的例子中,泛型形参没有什么约束,我们可以对泛型传入任何值,但在实际中,或许有时候我们需要为泛型增加某些特定的约束。

定义类型参数时增加一个限制,约束这个类型参数必须继承自特定的类,或遵守一个特定的协议或合成协议,这就叫做类型约束。

语法格式:

<类型形参1:父类,类型形参2:协议,类型形参3:protocol<协议1,协议2>,..>

Where语句

where语句要求一个关联类型遵循一个特定的协议,或那个特定的类型参数和关联类型可以是相同的

<类型形参:父类型,类型形参2:协议,…where 条件>

2019-04-26 10:13:00 weixin_33725126 阅读数 5

一、swift泛型介绍

泛型是为swift编程灵活性的一种语法,在函数、枚举、结构体、类中都得到充分的应用,它的引入可以起到占位符的作用,当类型暂时不确定时,只有等到调用函数时才能确定具体类型的时候可以引入泛型。
我们实际上已经使用过泛型了,例如:swift的Array和Dictionary类型都是泛型集

二、swift泛型使用

swift泛型相关使用可分为以下几点:
1.泛型函数
2.泛型类型
3.泛型约束
4.泛型协议

1.泛型函数,函数参数或返回值类型用泛型表示

//泛型函数定义式
func 函数名<泛型1,泛型2,......>(形参列表)->返回值类型
{
 // 函数体...
}

2.泛型类型,在定义类型时使用泛型

使用也和泛型函数差不多,就是再类型名后面加上<泛型1,泛型2,...>,然后在类型里面直接使用泛型即可

// 定义一个泛型结构体,用于压栈和出栈,泛型类型可以使用到类、结构体、枚举等各种类型
struct Stack<T> {
// 栈在这里是个数组存储形式,数组中存储的数据类型是泛型类型
  var items = [T]()
  // 因为压栈会修改实例值,需要加上mutating关键字
  mutating func push(item: T) {
    items.append(item)
  }
  // 因为出栈会修改实例值,需要加上mutating关键字
  mutating func pop() -> T {
    return items.removeLast()
  }
}

3.泛型约束,为泛型类型添加约束

泛型约束大致分为以下几种:
1.继承约束,泛型类型必须是某个类的子类类型
2.协议约束,泛型类型必须遵循某种协议
3.条件约束,泛型类型必须满足某种条件
约束的大概使用格式
约束的大概使用格式

//继承约束使用格式

func 函数名<泛型: 继承父类>(参数列表) -> 返回值 {
    //函数体,泛型类型是某个类的子类类型
}
//协议约束使用格式
func 函数名<泛型: 协议>(参数列表) -> 返回值 {
    //函数体,泛型类型遵循某些协议
}
//条件约束使用格式
func 函数名<泛型1, 泛型2 where 条件>(参数列表) -> 返回值 {
    //函数体,泛型类型满足某些条件
}

4.泛型协议和条件约束

//定义一个泛型协议,和其他泛型使用方式不同,这里泛型是以关联类型形式使用的
protocol Stackable{
    //声明一个关联类型,使用typealias关键字
    typealias ItemType
    mutating func push(item:ItemType)
    mutating func pop() -> ItemType
}
 
struct Stack<T>:Stackable{
    var store = [T]()
    mutating func push(item:T){//实现协议的push方法要求
        store.append(item)
    }
    mutating func pop() -> T {//实现协议的pop方法要求
        return store.removeLast()
    }
}

转载于:https://www.jianshu.com/p/0fc8dc64b280

2018-05-29 14:49:00 weixin_33888907 阅读数 7

The other difference between a generic function and a nongeneric function is that the generic function’s name (swapTwoValues(_:_:)) is followed by the placeholder type name (T) inside angle brackets (<T>). The brackets tell Swift that T is a placeholder type name within the swapTwoValues(_:_:) function definition. Because T is a placeholder, Swift doesn’t look for an actual type called T.

 

  • func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
  •     let temporaryA = a
  •     a = b
  •     b = temporaryA
  • }

 

  • var someInt = 3
  • var anotherInt = 107
  • swapTwoValues(&someInt, &anotherInt)
  • // someInt is now 107, and anotherInt is now 3
  •  
  • var someString = "hello"
  • var anotherString = "world"
  • swapTwoValues(&someString, &anotherString)

 

协议不能初始化,所以协议中的泛型使用inffer技术和typealias技术来指定

 

 

Generic Types

  • struct Stack<Element> {
  •     var items = [Element]()
  •     mutating func push(_ item: Element) {
  •         items.append(item)
  •     }
  •     mutating func pop() -> Element {
  •         return items.removeLast()
  •     }
  • }

 

  • var stackOfStrings = Stack<String>()
  • stackOfStrings.push("uno")
  • stackOfStrings.push("dos")
  • stackOfStrings.push("tres")
  • stackOfStrings.push("cuatro")
  • // the stack now contains 4 strings

 

 

Extending a Generic Type

  • extension Stack {
  •     var topItem: Element? {
  •         return items.isEmpty ? nil : items[items.count - 1]
  •     }
  • }

 

Type Constraints

 

  • func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
  •     for (index, value) in array.enumerated() {
  •         if value == valueToFind {
  •             return index
  •         }
  •     }
  •     return nil
  • }

 

  • let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])
  • // doubleIndex is an optional Int with no value, because 9.3 isn't in the array
  • let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
  • // stringIndex is an optional Int containing a value of 2

 

 

Associated Types

 

  • protocol Container {
  •     associatedtype Item
  •     mutating func append(_ item: Item)
  •     var count: Int { get }
  •     subscript(i: Int) -> Item { get }
  • }

 

  • struct IntStack: Container {
  •     // original IntStack implementation
  •     var items = [Int]()
  •     mutating func push(_ item: Int) {
  •         items.append(item)
  •     }
  •     mutating func pop() -> Int {
  •         return items.removeLast()
  •     }
  •     // conformance to the Container protocol
  •     typealias Item = Int
  •     mutating func append(_ item: Int) {
  •         self.push(item)
  •     }
  •     var count: Int {
  •         return items.count
  •     }
  •     subscript(i: Int) -> Int {
  •         return items[i]
  •     }
  • }

type inference

 

Thanks to Swift’s type inference, you don’t actually need to declare a concrete Item of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate Item to use, simply by looking at the type of the append(_:) method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias Item = Int line from the code above, everything still works, because it’s clear what type should be used for Item.

 

  • struct Stack<Element>: Container {
  •     // original Stack<Element> implementation
  •     var items = [Element]()
  •     mutating func push(_ item: Element) {
  •         items.append(item)
  •     }
  •     mutating func pop() -> Element {
  •         return items.removeLast()
  •     }
  •     // conformance to the Container protocol
  •     mutating func append(_ item: Element) {
  •         self.push(item)
  •     }
  •     var count: Int {
  •         return items.count
  •     }
  •     subscript(i: Int) -> Element {
  •         return items[i]
  •     }
  • }

Extending an Existing Type to Specify an Associated Type

  • extension Array: Container {}

Array’s existing append(_:) method and subscript enable Swift to infer the appropriate type to use for Item, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container.

 

 

Adding Constraints to an Associated Type

  • protocol Container {
  •     associatedtype Item: Equatable
  •     mutating func append(_ item: Item)
  •     var count: Int { get }
  •     subscript(i: Int) -> Item { get }
  • }

To conform to this version of Container, the container’s Item type has to conform to the Equatable protocol.

 

Using a Protocol in Its Associated Type’s Constraints

A protocol can appear as part of its own requirements. For example, here’s a protocol that refines the Container protocol, adding the requirement of a suffix(_:) method. The suffix(_:) method returns a given number of elements from the end of the container, storing them in an instance of the Suffix type.

  • protocol SuffixableContainer: Container {
  •     associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
  •     func suffix(_ size: Int) -> Suffix
  • }

In this protocol, Suffix is an associated type, like the Item type in the Container example above. Suffix has two constraints: It must conform to the SuffixableContainer protocol (the protocol currently being defined), and its Item type must be the same as the container’s Item type. The constraint on Item is a generic where clause, which is discussed in Associated Types with a Generic Where Clause below.

Here’s an extension of the Stack type from Strong Reference Cycles for Closures above that adds conformance to the SuffixableContainer protocol:

  • extension Stack: SuffixableContainer {
  •     func suffix(_ size: Int) -> Stack {
  •         var result = Stack()
  •         for index in (count-size)..<count {
  •             result.append(self[index])
  •         }
  •         return result
  •     }
  •     // Inferred that Suffix is Stack.
  • }
  • var stackOfInts = Stack<Int>()
  • stackOfInts.append(10)
  • stackOfInts.append(20)
  • stackOfInts.append(30)
  • let suffix = stackOfInts.suffix(2)
  • // suffix contains 20 and 30

 

 

Generic Where Clauses Type constraints

  • func allItemsMatch<C1: Container, C2: Container>
  •     (_ someContainer: C1, _ anotherContainer: C2) -> Bool
  •     where C1.Item == C2.Item, C1.Item: Equatable {
  •        
  •         // 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're equivalent.
  •         for i in 0..<someContainer.count {
  •             if someContainer[i] != anotherContainer[i] {
  •                 return false
  •             }
  •         }
  •        
  •         // All items match, so return true.
  •         return true
  • }

 

  • extension Container where Item: Equatable {
  •     func startsWith(_ item: Item) -> Bool {
  •         return count >= 1 && self[0] == item
  •     }
  • }

 

Associated Types with a Generic Where Clause

  • protocol Container {
  •     associatedtype Item
  •     mutating func append(_ item: Item)
  •     var count: Int { get }
  •     subscript(i: Int) -> Item { get }
  •    
  •     associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
  •     func makeIterator() -> Iterator
  • }

 

2018-03-22 22:30:00 weixin_33895475 阅读数 9

前言

  • 在 Swift 语言中,泛型可以说是用的最广最强大的特性之一,因为在 Swift 语言本身的语言底层大量的使用了泛型。

  • 泛型使得同样的操作可以应用于不同的数据类型。

    • 泛型编程的实现是我们程序在另一种抽象层次上的提升。
    • 类是现实世界事物的抽象,而泛型则是现实世界行为的抽象。

1、节点泛型

  • Swift 中的泛型同其它语言相同,用一对尖括号 < > 来声明泛型,尖括号中通常使用 TUV 等这样的大写字母来表示 “节点” 类型。

  • 使用泛型作为参数的函数叫做泛型函数。

    • 泛型函数在声明时使用节点类型命名来替代实际的类型名,并在泛型函数名后面插入节点类型的声明。
    • 节点类型在定义时不表示任何具体类型,在函数被调用时会根据传入的实际类型来指定自身的类型。

      func 函数名<T>(参数名1: T, 参数名2: T, ...) -> T {
      
          函数体 .....
      
          return 返回值
      }
  • 1)如果函数的列表中只有一个字母,如 T,虽然具体的类型不需要指定,但是函数中每个节点类型的参数(函数参数或返回值类型)必须是相同类型的。

    func show<T>(para1: T, para2: T) {
        print("\(para1)" + " \(para2)")
    }
    // 在调用时两个参数必须是相同的
    show(para1: 1, para2: 2)                        // 1 2
    show(para1: "xiaoming", para2: "xiaobai")       // xiaoming xiaobai
  • 2)如果要定义多个不同类型的泛型,则需要在尖括号中加入多个节点 <T, U, V ...>

    func show<T, U>(para1: T, para2: U) {
        print("\(para1)" + " \(para2)")
    }
    // 在调用时两个参数可以不同
    show(para1: "xiaoming", para2: 18) // xiaoming 18
  • 3)你还可以对节点进行一些限制,比如要求泛型遵守某些协议。

    // Swift 中数组的判等函数
    public func ==<Element: Equatable>(lhs: [Element], rhs: [Element]) -> Bool {...} 
    • Element 是使用节点声明的,它代表一个泛型,可以看到这里的泛型名是 Element,相比上面的 TUV 等要长的多。这是因为此处的 Element 不仅仅是一个占位符的作用,它还声明了这个泛型代表数组中的元素类型,具有具体的意义。
  • 4)有时候节点中的泛型需要有更多的限制,需要使用 where 子句来补充约束条件。

    • 在 Swift 3.0 之前。

      func anyCommonElements<T: SequenceType, U: SequenceType where
          T.Generator.Element: Equatable,
          T.Generator.Element == U.Generator.Element>(lhs: T, _ rhs: U) -> Bool {
          ...
      }
    • 在 Swift 3.0 及之后 where 子句被移动到了参数列表的后面。

      func anyCommonElements<T: SequenceType, U: SequenceType>(lhs: T, _ rhs: U) -> Bool 
          where
              T.Generator.Element: Equatable,
              T.Generator.Element == U.Generator.Element{
          ...
      }

2、泛型协议

  • 1)除了节点式声明泛型外,还有其它方式声明一个泛型,比如使用关键字 associatedtype(关联类型)(Swift 3.0 之前是 typealias 关键字)。

    protocol SomeProtocol {
    
        associatedtype Element
    
        func elementMethod1(element: Element)
        func elementMethod2(element: Element)
    }
    • 这里虽然没有出现节点语法,但上面的协议确实是个不折不扣的泛型协议,Element 起到了占位符的作用,指示了某种类型。
    • 根据协议的规则,协议 SomeProtocol 的遵守者必须实现上面两个方法,Element 隐式的约束了两个方法的参数必须是相同类型的。
    • 不用刻意指定 Element 的具体类型,编译器会根据实现方法时传入的参数类型确定 Element 的具体类型。
    • 在实现的时候不能直接用 ElementElement 只能存在于具体实现之前。泛型协议依靠遵守协议中协议方法的的具体实现来明确泛型的类型。
    • 协议的遵守者如果遵守了多个协议,那么这些协议的关联类型名称不能重复,否则编译器会报错。

      struct TestStruct: SomeProtocol {
      
          func elementMethod1(element: String) {
              print("elementFromMethod1: \(element)")
          }
      
          func elementMethod2(element: String) {
              print("elementFromMethod2: \(element)")
          }
      }
      TestStruct().elementMethod1(element: "qwert")   // elementFromMethod1: qwert
      TestStruct().elementMethod2(element: "asdfg")   // elementFromMethod2: asdfg
  • 2)类似于 associatedtype 的还有 Self 关键字,代表了协议遵守者本身的的类型,适用于 “比较” 这类方法,其必须传入另一个相同类型的参数才有意义。

    protocol CanCompare {
    
        func isBigger(other: Self) -> Bool
    }
    struct BoxInt: CanCompare {
    
        var intValue: Int
    
        func isBigger(other: BoxInt) -> Bool {
            return self.intValue > other.intValue
        }
    }
    BoxInt(intValue: 3).isBigger(other: BoxInt(intValue: 2))    // true

3、泛型对象

  • 关联类型和 Self 关键字都是在协议层面的泛型,此外还有对象层面的泛型,比如我们常用的数组就是对象层面的泛型定义的,效果相同。

  • 如果不使用协议,一个泛型对象风格的结构体定义如下。

    struct TestStruct<T: Comparable> {
    
        func elementMethod1(element: T) {
            print("elementFromMethod1: \(element)")
        }
    
        func elementMethod2(element: T) {
            print("elementFromMethod2: \(element)")
        }
    }
    • 泛型应该用在声明中,调用时版本中的泛型已经被 “特化” 成具体的泛型。泛型对象通过构造器初始化时明确明确泛型的类型,这些类型都是具体的。
    • 如果在实现时 “嵌套” 一个泛型,那么会导致泛型无法特化。比如数组本身是泛型的,在声明数组类型时传入了另一个泛型,那么你将无法初始化该数组。

      let test = TestStruct<Int>()
      test.elementMethod1(1)

4、泛型方法

  • 方法中的泛型使用节点表示法,作用域只在本方法内。

    struct TestStruct {
    
        func elementMethod1<T: Comparable>(element: T) {
            print("elementFromMethod1: \(element)")
        }
    
        func elementMethod2<T: Comparable>(element: T) {
            print("elementFromMethod2: \(element)")
        }
    }
    • 这样同一个实例的相同方法就可以接受不同的参数类型了。

      let test = TestStruct()
      test.elementMethod1(element: 1)
      test.elementMethod1(element: "abc")

5、协议中的 where 关键字

  • where 关键字可以与 for-in 循环配合实现筛选,where 同样可以用在协议扩展中,使得定义在协议扩展中的方法可以对某些遵守者 “隐身”,而对另一些遵守者 “可见”。

  • 协议的遵守者如果遵守了多个协议,那么这些协议的关联类型名称不能重复,否则编译器会报错。

    protocol SomeProtocol {
    
        associatedtype OwnElement
    
        func elementMethod1(element: OwnElement)
        func elementMethod2(element: OwnElement)
    }
  • 1)where 关键字可以与 Self 关键字配合,在协议扩展中定义一个新方法,指定当协议的遵守者是集合类型时,必须打印出遵守者的元素个数。

    extension SomeProtocol where Self: Collection {
    
        func showCount() {
            print(self.count)
        }
    }
    • where 的限制是强制的,他是一个编译器强制的开关。虽然在协议的扩展中并不能知晓会有哪些对象遵守了该协议,但是一旦使用了 where,那么就表明在扩展的作用域中 where 后面的语句默认实现了。
    • Array 类型已经遵守了 Collection 协议,所以如果让 Array 同时遵守 SomeProtocol,那么它就能获得 showCount 方法。

      extension Array: SomeProtocol {
      
          func elementMethod1(element: String) {
              print("elementFromMethod1: \(element)")
          }
      
          func elementMethod2(element: String) {
              print("elementFromMethod2: \(element)")
          }
      }
      [1, 2, 3].showCount()       // 3
  • 2)where 所指定的力度范围还可以继续缩小,可以使用 where 限定协议中的关联类型。

    extension SomeProtocol where OwnElement: SignedNumeric {
    
        func showElement() {
            print(OwnElement.self)
        }
    }

Swift泛型

阅读数 12

Swift: 泛型

阅读数 9

Swift 泛型

阅读数 6

swift 泛型

阅读数 259

Swift泛型

阅读数 1613

没有更多推荐了,返回首页