16-泛型

作者: 二斤寂寞 | 来源:发表于2023-04-12 16:34 被阅读0次

泛型(Generics)

  • 泛型可以将类型参数化,提高代码复用率,减少代码量
func swapValues<T>(_ a: inout T, _ b: inout T) {
     (a, b) = (b, a)                                              
} 
var i1 = 10
var i2 = 20
swapValues(&i1, &i2)

var d1 = 10.0
var d2 = 20.0
swapValues(&d1, &d2)

struct Date {
 var year = 0, month = 0, day = 0                                            
}

var dd1 = Date(year: 2011, month: 9, day: 10) 
var dd2 = Date(year: 2012, month: 10, day: 11) 
swapValues(&dd1, &dd2) 
  • 泛型函数赋值给变量
func test<T1, T2>(_ t1: T1, _ t2: T2) {} 
var fn: (Int, Double) -> () = test 

泛型

class Stack<E> {
   var elements = [E]()
   func push(_ element: E) { elements.append(element) } func pop() -> E { elements.removeLast() }
   func top() -> E { elements.last! }
   func size() -> Int { elements.count } 
} 
class SubStack<E> : Stack<E> {} 

\color{green}{相当于修改结构体内存布局,需要加 mutating}

struct Stack<E> {
 var elements = [E]()
 mutating func push(_ element: E) { elements.append(element) } 
 mutating func pop() -> E { elements.removeLast() } }    
 func top() -> E { elements.last! } 
 func size() -> Int { elements.count }                                          
} 
var stack = Stack<Int>()
stack.push(11)
stack.push(22)
stack.push(33)
print(stack.top()) // 33
print(stack.pop()) // 33
print(stack.pop()) // 22
print(stack.pop()) // 11
print(stack.size()) // 0
enum Score<T> {
    case point(T)
    case grade(String)
}
let score0 = Score<Int>.point(100) 
let score1 = Score.point(99)
let score2 = Score.point(99.5) 
let score3 = Score<Int>.grade("A") 

泛型的本质:

  • c++代码本质 根据类型创建多个。
func swapValues<T>(_ a: inout T, _ b: inout T) {
     (a, b) = (b, a)                                              
} 

func swapValues<Int>(_ a: inout Int, _ b: inout Int) {
     (a, b) = (b, a)                                              
} 

func swapValues<Double>(_ a: inout Double, _ b: inout Double) {
     (a, b) = (b, a)                                              
} 
  • 看下swift


    image.png
    image.png
    image.png

不同的类型,函数地址一样。metadata源类型。可以自研下。

关联类型(Associated Type)

  • 关联类型的作用:给协议中用到的类型定义一个占位名称

  • 协议中可以拥有多个关联类型

protocol Stackable {
   associatedtype Element // 关联类型 
   mutating func push(_ element: Element) 
   mutating func pop() -> Element
   func top() -> Element
   func size() -> Int                                 
} 
class Stack<E> : Stackable {
    // typealias Element = E
    var elements = [E]()
    func push(_ element: E) {                                     
        elements.append(element) 
    } 

    func pop() -> E { elements.removeLast() } 
    func top() -> E { elements.last! }
    func size() -> Int { elements.count } 
}
class StringStack : Stackable {
    // 给关联类型设定真实类型
    // typealias Element = String
    var elements = [String]()
    func push(_ element: String) { elements.append(element) } func pop() -> String { elements.removeLast() }                                          
    func top() -> String { elements.last! } 
    func size() -> Int { elements.count } }      
} 

var ss = StringStack()
ss.push("Jack")
ss.push("Rose")

类型约束

protocol Runnable { }
class Person { }
func swapValues<T : Person & Runnable>(_ a: inout T, _ b: inout T) { 
    (a, b) = (b, a)
}
protocol Stackable {
     associatedtype Element: Equatable                                             
}
class Stack<E : Equatable> : Stackable { typealias Element = E } 
func equal<S1: Stackable, S2: Stackable>(_ s1: S1, _ s2: S2) -> Bool 
    where S1.Element == S2.Element, S1.Element : Hashable {
     return false                                   
} 
var stack1 = Stack<Int>()
 var stack2 = Stack<String>()
 // error: requires the types 'Int' and 'String' be equivalent equal(stack1, stack2) 

协议类型的注意点

protocol Runnable {}
class Person : Runnable {}
class Car : Runnable {}

func get(_ type: Int) -> Runnable { 
    if type == 0 { 
        return Person()
    }
    return Car()
}
var r1 = get(0)
var r2 = get(1)
  • 如果协议中有associatedtype
protocol Runnable {
   associatedtype Speed
   var speed: Speed { get }
}
class Person : Runnable {
   var speed: Double { 0.0 }
}
class Car : Runnable {
   var speed: Int { 0 }
} 
image.png image.png

泛型解决

  • 解决方案1:使用泛型
func get<T : Runnable>(_ type: Int) -> T {
  if type == 0 {
     return Person() as! T
  }
  return Car() as! T
}
var r1: Person = get(0)
var r2: Car = get(1)

不透明类型(Opaque Type)

  • 解决方案2:使用some关键字声明一个不透明类型
func get(_ type: Int) -> some Runnable { Car() }
var r1 = get(0)
var r2 = get(1)
  • some限制只能返回一种类型
image.png

some

  • some除了用在返回值类型上,一般还可以用在属性类型上
protocol Runnable { associatedtype Speed }
class Dog : Runnable { typealias Speed = Double }
class Person {
   var pet: some Runnable {
     return Dog() 
   } 
} 

可选项的本质

  • 可选项的本质是enum类型
public enum Optional<Wrapped> : ExpressibleByNilLiteral { 
    case none                                              
    case some(Wrapped)
    public init(_ some: Wrapped)                                               
} 
var age: Int? = 10
var age0: Optional<Int> = Optional<Int>.some(10) var age1: Optional = .some(10)
var age2 = Optional.some(10)
var age3 = Optional(10)
age = nil
age3 = .none 
var age: Int? = nil
var age0 = Optional<Int>.none 
var age1: Optional<Int> = .none 
var age: Int? = .none
age = 10
age = .some(20)
age = nil
switch age {
case let v?:
    print("some", v)
case nil:
    print("none")
}
switch age {
case let .some(v):
    print("some", v)
case .none:
    print("none")
}

可选项的本质

var age_: Int? = 10
var age: Int?? = age_
age = nil

var age0 = Optional.some(Optional.some(10)) age0 = .none
var age1: Optional<Optional> = .some(.some(10)) age1 = .none 
var age: Int?? = 10
var age0: Optional<Optional> = 10 

相关文章

  • [Swift5.1] 16-泛型

    泛型(Generics) 泛型函数 泛型可以将类型参数化,提高代码复用率,减少代码量 T代表 不确定类型参数 泛型...

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

网友评论

      本文标题:16-泛型

      本文链接:https://www.haomeiwen.com/subject/apnbddtx.html