Error[8]: Undefined offset: 208, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

概述Kotlin 君和 Swift 君在一个团队一起开发已经很久了,由于平台的差异性,他们经常会进行一些技术上的交流(PK),「Kotlin vs. Swift」 系列就是他们在互相切磋时的语录。内容会由简及深,慢慢深入。 技术漫谈 Swift: Hi, Kotlin 君, Swift 4 发布了,我们今天就基于 Swift 4 的新语法来讨论一下接口吧? Kotlin: 好啊,接口对我们开发来说是个

Kotlin 君和 Swift 君在一个团队一起开发已经很久了,由于平台的差异性,他们经常会进行一些技术上的交流(PK),「Kotlin vs. Swift」 系列就是他们在互相切磋时的语录。内容会由简及深,慢慢深入。


技术漫谈


Swift:


Hi,Kotlin 君,Swift 4 发布了,我们今天就基于 Swift 4 的新语法来讨论一下接口吧?


Kotlin:


好啊,接口对我们开发来说是个很重要的概念。设计模式中要求我们写代码要遵循依赖倒置原则,就是程序要依赖于抽象接口,不要依赖于具体实现,也就是要求我们要面向接口编程。


Swift:


是的,在 Swift 中,接口被称为协议(即 Protocol ),苹果大大强化了 Protocol 在这门语言中的地位,整个 Swift 标准库也是基于 Protocol 来设计的,可以说 Swift 是一门面向 protocol 编程的语言。


Kotlin:


听起来好流比,那来说说你们是怎么定义接口的?


Swift:


我们用 Protocol 关键字来定义接口:


protocol SomeProtocol {

    func f()

}


你们呢?


Kotlin:


我们同 Java 一样,用 interface 关键字来定义接口:


interface MyInterface {

    fun f()

}


Swift:


嗯,看起来就是关键字不一样。你们怎么实现接口呢?


Kotlin:


一个类要实现某个接口,需要在类型名称后加上协议名称,中间以冒号(:)分隔:


class MyClass: MyInterface {

    overrIDe fun f() {

       // 具体实现

    }

}


一个类或者对象可以实现一个或多个接口。实现多个接口时,各接口之间用逗号(,)分隔.


Swift:


我们也是一样的,只是我们不需要写 overrIDe 关键字,只有当子类复写父类的方法或计算属性时才需要用 overrIDe 修饰。另外,我们还可以通过扩展类型来实现协议:


class MyClass {

    //...类的定义

}


extension MyClass: SomeProtocol {

    func f() {

        // 具体实现

}


Kotlin:


这意味着你们不用修改原有类型,就可以让原有类型符合某个协议了,甚至可以扩展标准库中的某个基础类型来实现自定义的协议。这很符合开闭原则嘛。


Swift:


是啊,牛不牛 。


我们实现协议的类型除了 class 外,还可以是 struct 或 enum。


Kotlin:


Kotlin 没有结构体的概念, enum 也可以实现接口。


来说说你们的接口中可以声明哪些东西吧?


Swift:


我们可以在协议中声明属性和方法,用 var 关键字来声明变量属性,并在属性声明后加上 { set get } 来表示属性是可读可写的,用 { get } 来表示属性是只读的。


协议里面声明的属性和方法一定是抽象的,不能有实现,由符合协议的类型来提供所有属性和方法的实现。


Kotlin:


我们也可以声明属性和方法,而且 Kotlin 可以直接在接口中为属性和方法提供默认实现:


interface MyInterface {

    val prop: Int // 抽象的

    val propertyWithImplementation: String

        get() = "foo"


    fun foo() {

        print(prop)

    }

}


class MyClass : MyInterface {

    overrIDe val prop: Int = 29

}


Swift:


虽然我们不能在协议中直接提供属性和方法的默认实现,但是我们可以通过协议扩展来达到此目的。


protocol MyProtocol {

    var prop: Int { get set }

    var propertyWithImplementation: String { get }

    func foo()

extension MyProtocol {

    var propertyWithImplementation: String {

        return "foo"

    

    func foo() {

class MyClass: MyProtocol {

    var prop: Int = 29

}


Kotlin:


哇~,你们这个协议扩展有点厉害了。


Swift:


是的,正是这个特性,才使得我们面向协议编程成为可能。我们甚至可以在扩展中添加协议里没有定义过的方法和属性。


    func isExceed() -> Bool {

        return prop > 30

}

let instance = MyClass()

print(instance.isExceed())

// false


Kotlin:


这就意味着你们也有能力扩展标准库里的协议了,可以很方便的给标准库里的协议添加新的方法和属性。


Swift:


聪明,确实是这样。不仅如此,在扩展协议的时候,还可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。


protocol TextRepresentable {

    var textualDescription: String { get }

struct Hamster: TextRepresentable {

    var name: String

    var textualDescription: String {

        return "A hamster named \(name)"

extension Collection where Iterator.Element: TextRepresentable {

        let itemsAsText = self.map {         return "[" + itemsAsText.joined(separator: ",") + "]".textualDescription }

let hamsters = [Hamster(name: "Jim"),Hamster(name: "Merry")]

print(hamsters.textualDescription)

// [A hamster named Jim,A hamster named Merry]

这里扩展了 Swift 标准库中的 Collection 协议,但是限制只适用于集合中的元素遵循了 TextRepresentable 协议的情况。 因为 Swift 中 Array 符合 Collection 协议,而 Hamster 类型又符合 TextRepresentable 协议,所以 hamsters 可以使用 textualDescription 属性得到数组内容的文本表示。


Kotlin:


赞啊~,你们这个协议扩展太强大了,不仅可以扩展自己定义的协议,还可以扩展标准库中的协议,怪不得苹果称 Swift 是面向协议编程的语言。


Swift 在实现多个协议时,会不会有不同协议带来同名方法或属性的冲突的问题?


Swift:


我们还不能很好地处理多个协议的冲突问题。


Kotlin:


Kotlin 可以,Kotlin 有一套规则来处理这样的冲突。在 Kotlin 中,如果一个类从它的直接超类继承相同成员的多个实现(由于接口函数可以有实现),它必须覆盖这个成员并提供其自己的实现。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super。


open class A {


    open fun f() { print("A") }

    fun a() { print("a") }

interface B {

    fun f() { print("B") } // interface members are 'open' by default

    fun b() { print("b") }

class C() : A(),B {

    // The compiler requires f() to be overrIDden:

    overrIDe fun f() {

        super<A>.f() // call to A.f()

        super<B>.f() // call to B.f()

}

Swift:


这个好赞,可以不怕名字冲突了 。


Kotlin 的接口中可以声明类方法吗?


Kotlin:


Kotlin 里面已经没有类方法的概念了。


Swift:


我们可以在协议中使用 static 关键字来声明类型方法,如果实现该协议的类型是 class 类型,则在实现类中除了用 static 来修饰类型方法外,也可以使用 class关键字.


    static func someTypeMethod()


class SomeClass: SomeProtocol {

    // 这里也可以用 static 修饰,区别是 static 修饰的属性

    // 或方法不能被子类复写,class 修饰的可以被子类复写

    class func someTypeMethod() {

        print("type method")

}

Kotlin:


我们的接口虽然不支持类方法,但是我们可以给接口中定义的方法的参数设置默认值。


Swift:


这。。。我们不支持为协议中的方法的参数提供默认值。


Kotlin:


方法参数的默认值必须定义在接口中,在实现类或对象实现该方法时,不能为函数提供默认值。同时接口的中函数不能用 JVMOverrIDe 注解修饰,所以接口中定义的带有默认值的参数,不能为 Java 生成重载方法,如果接口是定义在库里面,Kotlin 的实现也无法使用自动重载功能,需要手动重载。


interface IDownload{


    fun(url: String,isSupportBreakpointC: Boolean = true)

class DownloadImpl: IDownload{

    overrIDe fun(url: String,isSupportBreakpointC: Boolean){

        

}

Swift:


这点算你强。


我们的协议中可以定义可变方法,如果协议中定义的实例方法会改变遵循该协议的类型的实例,那么需要在该方法前加 mutating 关键字,表示可以在该方法中修改它所属的实例以及实例的任意属性的值,例如:


protocol Togglable {


    mutating func toggle()

enum OnOffSwitch: Togglable {

    case off,on

    mutating func toggle() {

        switch self {

        case .off:

            self = .on

        case .on:

            self = .off

        }

}

var lightSwitch = OnOffSwitch.off

lightSwitch.toggle()

// lightSwitch 现在的值为 .On

Kotlin:


我们没这特性,这点你赢了。


Swift:


岂止如此,我们的协议中还可以要求遵循协议的类型实现指定的构造器:


protocol SomeProtocol {


    init(someParameter: Int)

class SomeClass: SomeProtocol {

    required init(someParameter: Int) {

        // initializer implementation goes here

}

在符合协议的类中实现构造器,必须在构造器实现前加上 required 修饰符。使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。 如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符,因为 final 类不能有子类.


协议还可以为遵循协议的类型定义可失败构造器。


Kotlin:


好吧,我们不可以在接口中声明构造器。


Swift:


你们的接口可以继承吗?


Swift 中协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求.


Kotlin:


当然可以,这是基本的用法好伐。


Swift:


好吧。。我们还可以通过让协议继承 AnyObject 协议来限制协议只能被 Class 类型遵循,而结构体或枚举不能遵循该协议。


Kotlin:


我们并没有这种限制,接口可以被类和枚举实现。


Swift:


你们的接口可以组合吗?


Swift 可以采用 & 符号将多个协议进行组合:


protocol named {


    var name: String { get }

protocol Aged {

    var age: Int { get }

struct Person: named,Aged {

    var name: String

    var age: Int

func wishHappyBirthday(to celebrator: named & Aged) {

    print("Happy birthday,\(celebrator.name),you're \(celebrator.age)!")

let birthdayPerson = Person(name: "Malcolm",age: 21)

wishHappyBirthday(to: birthdayPerson)

// Prints "Happy birthday,Malcolm,you're 21!"

这里 wishHappyBirthday(to:) 函数的参数类型为 named & Aged,这意味着它不关心参数的具体类型,只要参数符合这两个协议即可。当然也可以给组合的协议指定一个别名:typealias Property = named & Aged


Kotlin:


[+++]


666,你们的协议真是玩出花了,这个功能我们也没有 总结

以上是内存溢出为你收集整理的Swift vs. Kotlin 漫谈系列之接口全部内容,希望文章能够帮你解决Swift vs. Kotlin 漫谈系列之接口所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
Swift vs. Kotlin 漫谈系列之接口_app_内存溢出

Swift vs. Kotlin 漫谈系列之接口

Swift vs. Kotlin 漫谈系列之接口,第1张

概述Kotlin 君和 Swift 君在一个团队一起开发已经很久了,由于平台的差异性,他们经常会进行一些技术上的交流(PK),「Kotlin vs. Swift」 系列就是他们在互相切磋时的语录。内容会由简及深,慢慢深入。 技术漫谈 Swift: Hi, Kotlin 君, Swift 4 发布了,我们今天就基于 Swift 4 的新语法来讨论一下接口吧? Kotlin: 好啊,接口对我们开发来说是个

Kotlin 君和 Swift 君在一个团队一起开发已经很久了,由于平台的差异性,他们经常会进行一些技术上的交流(PK),「Kotlin vs. Swift」 系列就是他们在互相切磋时的语录。内容会由简及深,慢慢深入。


技术漫谈


Swift:


Hi,Kotlin 君,Swift 4 发布了,我们今天就基于 Swift 4 的新语法来讨论一下接口吧?


Kotlin:


好啊,接口对我们开发来说是个很重要的概念。设计模式中要求我们写代码要遵循依赖倒置原则,就是程序要依赖于抽象接口,不要依赖于具体实现,也就是要求我们要面向接口编程。


Swift:


是的,在 Swift 中,接口被称为协议(即 Protocol ),苹果大大强化了 Protocol 在这门语言中的地位,整个 Swift 标准库也是基于 Protocol 来设计的,可以说 Swift 是一门面向 protocol 编程的语言。


Kotlin:


听起来好流比,那来说说你们是怎么定义接口的?


Swift:


我们用 Protocol 关键字来定义接口:


protocol SomeProtocol {

    func f()

}


你们呢?


Kotlin:


我们同 Java 一样,用 interface 关键字来定义接口:


interface MyInterface {

    fun f()

}


Swift:


嗯,看起来就是关键字不一样。你们怎么实现接口呢?


Kotlin:


一个类要实现某个接口,需要在类型名称后加上协议名称,中间以冒号(:)分隔:


class MyClass: MyInterface {

    overrIDe fun f() {

       // 具体实现

    }

}


一个类或者对象可以实现一个或多个接口。实现多个接口时,各接口之间用逗号(,)分隔.


Swift:


我们也是一样的,只是我们不需要写 overrIDe 关键字,只有当子类复写父类的方法或计算属性时才需要用 overrIDe 修饰。另外,我们还可以通过扩展类型来实现协议:


class MyClass {

    //...类的定义

}


extension MyClass: SomeProtocol {

    func f() {

        // 具体实现

}


Kotlin:


这意味着你们不用修改原有类型,就可以让原有类型符合某个协议了,甚至可以扩展标准库中的某个基础类型来实现自定义的协议。这很符合开闭原则嘛。


Swift:


是啊,牛不牛 。


我们实现协议的类型除了 class 外,还可以是 struct 或 enum。


Kotlin:


Kotlin 没有结构体的概念, enum 也可以实现接口。


来说说你们的接口中可以声明哪些东西吧?


Swift:


我们可以在协议中声明属性和方法,用 var 关键字来声明变量属性,并在属性声明后加上 { set get } 来表示属性是可读可写的,用 { get } 来表示属性是只读的。


协议里面声明的属性和方法一定是抽象的,不能有实现,由符合协议的类型来提供所有属性和方法的实现。


Kotlin:


我们也可以声明属性和方法,而且 Kotlin 可以直接在接口中为属性和方法提供默认实现:


interface MyInterface {

    val prop: Int // 抽象的

    val propertyWithImplementation: String

        get() = "foo"


    fun foo() {

        print(prop)

    }

}


class MyClass : MyInterface {

    overrIDe val prop: Int = 29

}


Swift:


虽然我们不能在协议中直接提供属性和方法的默认实现,但是我们可以通过协议扩展来达到此目的。


protocol MyProtocol {

    var prop: Int { get set }

    var propertyWithImplementation: String { get }

    func foo()

extension MyProtocol {

    var propertyWithImplementation: String {

        return "foo"

    

    func foo() {

class MyClass: MyProtocol {

    var prop: Int = 29

}


Kotlin:


哇~,你们这个协议扩展有点厉害了。


Swift:


是的,正是这个特性,才使得我们面向协议编程成为可能。我们甚至可以在扩展中添加协议里没有定义过的方法和属性。


    func isExceed() -> Bool {

        return prop > 30

}

let instance = MyClass()

print(instance.isExceed())

// false


Kotlin:


这就意味着你们也有能力扩展标准库里的协议了,可以很方便的给标准库里的协议添加新的方法和属性。


Swift:


聪明,确实是这样。不仅如此,在扩展协议的时候,还可以指定一些限制条件,只有遵循协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。


protocol TextRepresentable {

    var textualDescription: String { get }

struct Hamster: TextRepresentable {

    var name: String

    var textualDescription: String {

        return "A hamster named \(name)"

extension Collection where Iterator.Element: TextRepresentable {

        let itemsAsText = self.map {         return "[" + itemsAsText.joined(separator: ",") + "]".textualDescription }

let hamsters = [Hamster(name: "Jim"),Hamster(name: "Merry")]

print(hamsters.textualDescription)

// [A hamster named Jim,A hamster named Merry]

这里扩展了 Swift 标准库中的 Collection 协议,但是限制只适用于集合中的元素遵循了 TextRepresentable 协议的情况。 因为 Swift 中 Array 符合 Collection 协议,而 Hamster 类型又符合 TextRepresentable 协议,所以 hamsters 可以使用 textualDescription 属性得到数组内容的文本表示。


Kotlin:


赞啊~,你们这个协议扩展太强大了,不仅可以扩展自己定义的协议,还可以扩展标准库中的协议,怪不得苹果称 Swift 是面向协议编程的语言。


Swift 在实现多个协议时,会不会有不同协议带来同名方法或属性的冲突的问题?


Swift:


我们还不能很好地处理多个协议的冲突问题。


Kotlin:


Kotlin 可以,Kotlin 有一套规则来处理这样的冲突。在 Kotlin 中,如果一个类从它的直接超类继承相同成员的多个实现(由于接口函数可以有实现),它必须覆盖这个成员并提供其自己的实现。 为了表示采用从哪个超类型继承的实现,我们使用由尖括号中超类型名限定的 super,如 super。


open class A {


    open fun f() { print("A") }

    fun a() { print("a") }

interface B {

    fun f() { print("B") } // interface members are 'open' by default

    fun b() { print("b") }

class C() : A(),B {

    // The compiler requires f() to be overrIDden:

    overrIDe fun f() {

        super<A>.f() // call to A.f()

        super<B>.f() // call to B.f()

}

Swift:


这个好赞,可以不怕名字冲突了 。


Kotlin 的接口中可以声明类方法吗?


Kotlin:


Kotlin 里面已经没有类方法的概念了。


Swift:


我们可以在协议中使用 static 关键字来声明类型方法,如果实现该协议的类型是 class 类型,则在实现类中除了用 static 来修饰类型方法外,也可以使用 class关键字.


    static func someTypeMethod()


class SomeClass: SomeProtocol {

    // 这里也可以用 static 修饰,区别是 static 修饰的属性

    // 或方法不能被子类复写,class 修饰的可以被子类复写

    class func someTypeMethod() {

        print("type method")

}

Kotlin:


我们的接口虽然不支持类方法,但是我们可以给接口中定义的方法的参数设置默认值。


Swift:


这。。。我们不支持为协议中的方法的参数提供默认值。


Kotlin:


方法参数的默认值必须定义在接口中,在实现类或对象实现该方法时,不能为函数提供默认值。同时接口的中函数不能用 JVMOverrIDe 注解修饰,所以接口中定义的带有默认值的参数,不能为 Java 生成重载方法,如果接口是定义在库里面,Kotlin 的实现也无法使用自动重载功能,需要手动重载。


interface IDownload{


    fun(url: String,isSupportBreakpointC: Boolean = true)

class DownloadImpl: IDownload{

    overrIDe fun(url: String,isSupportBreakpointC: Boolean){

        

}

Swift:


这点算你强。


我们的协议中可以定义可变方法,如果协议中定义的实例方法会改变遵循该协议的类型的实例,那么需要在该方法前加 mutating 关键字,表示可以在该方法中修改它所属的实例以及实例的任意属性的值,例如:


protocol Togglable {


    mutating func toggle()

enum OnOffSwitch: Togglable {

    case off,on

    mutating func toggle() {

        switch self {

        case .off:

            self = .on

        case .on:

            self = .off

        }

}

var lightSwitch = OnOffSwitch.off

lightSwitch.toggle()

// lightSwitch 现在的值为 .On

Kotlin:


我们没这特性,这点你赢了。


Swift:


岂止如此,我们的协议中还可以要求遵循协议的类型实现指定的构造器:


protocol SomeProtocol {


    init(someParameter: Int)

class SomeClass: SomeProtocol {

    required init(someParameter: Int) {

        // initializer implementation goes here

}

在符合协议的类中实现构造器,必须在构造器实现前加上 required 修饰符。使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。 如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符,因为 final 类不能有子类.


协议还可以为遵循协议的类型定义可失败构造器。


Kotlin:


好吧,我们不可以在接口中声明构造器。


Swift:


你们的接口可以继承吗?


Swift 中协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求.


Kotlin:


当然可以,这是基本的用法好伐。


Swift:


好吧。。我们还可以通过让协议继承 AnyObject 协议来限制协议只能被 Class 类型遵循,而结构体或枚举不能遵循该协议。


Kotlin:


我们并没有这种限制,接口可以被类和枚举实现。


Swift:


你们的接口可以组合吗?


Swift 可以采用 & 符号将多个协议进行组合:


protocol named {


    var name: String { get }

protocol Aged {

    var age: Int { get }

struct Person: named,Aged {

    var name: String

    var age: Int

func wishHappyBirthday(to celebrator: named & Aged) {

    print("Happy birthday,\(celebrator.name),you're \(celebrator.age)!")

let birthdayPerson = Person(name: "Malcolm",age: 21)

wishHappyBirthday(to: birthdayPerson)

// Prints "Happy birthday,Malcolm,you're 21!"

这里 wishHappyBirthday(to:) 函数的参数类型为 named & Aged,这意味着它不关心参数的具体类型,只要参数符合这两个协议即可。当然也可以给组合的协议指定一个别名:typealias Property = named & Aged


Kotlin:



666,你们的协议真是玩出花了,这个功能我们也没有 总结

以上是内存溢出为你收集整理的Swift vs. Kotlin 漫谈系列之接口全部内容,希望文章能够帮你解决Swift vs. Kotlin 漫谈系列之接口所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1024725.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存