Swift vs. Kotlin 漫谈之扩展篇

转载自公众号 KotlinThree 里的一篇文章:https://mp.weixin.qq.com/s?__biz=MzU3MDA3NzMzOA==&mid=2247483719&idx=1&sn=9b4b3ab235777689aee0d6b4274da8bc&chksm=fcf5b8b2cb8231a41038d8820672c4e99039e4126597a7819efe8aeecd75015894cf918ad987&mpshare=1&scene=1&srcid=0703QSVj40BLsRG7R8BTtIyy#rd

引子

今年Google I/O 大会上最让广大Android开发者振奋的消息就是Kotlin了。虽然很早之前就关注了,但是由于工作太忙一直没有时间(其实是懒癌犯了)学习一下。现在成为了官方支持的开发语言,再不好好学学就真的说不过去了。
机缘巧合参加了沪江网举办的一场关于Kotlin开发Android的技术沙龙。他们团队在这个领域已经有了两年的技术积累,分享了很多非常实用的知识点与技巧。整个活动下来,我深深的感觉到学习这门语言给Android开发带来的效率上的提升与思维方式上的改变,等于是打开了一个新的局面。
活动负责人安利了自己开办的一个学习Kotlin的公众号:KotlinThree,以及对比同为移动端开发新语言的Swift的计划 Swift vs Kotlin。我当时就决定参与进来,跟优秀的人一起学习总是最快的,不是吗?
于是就有了这篇文章,跟志平同学第一次合作,而且Kotlin的知识掌握的也不是很扎实,所以写的一般。但毕竟是一个好的开始,希望后面能坚持下去。

Swift -vs- Kotlin: 扩展篇

脱单秘诀

Swift:

Kotlin 君,我看你最近加班多,都快没有时间谈恋爱了?你和你的女神近况怎么样?

Kotlin

Swift君,别闹。我们只是朋友关系;

Swift

傻子都看得出来你对你的女神有意思,看你单身20余载,恋爱经验匮乏,要不要我传授你撩妹秘诀?

Kotlin

懂我者Swift君也,快说说看;

Swift

以我们Swift为例,我们先定义一个人类,然后你就是kotliner和你女神angel

class Human {var name: Stringvar age: Intvar lover: Human?init(_ name:String, age: Int) {self.name = nameself.age = age}
}var kotliner = Human.init("Kotliner", age: 26)
var angel = Human.init("Angel", age: 27)

Kotlin

先定义一个Human是吧,好,我也完成了。

class Human(name:String){var lover: Human?constructor(name:String ,age: Int) : this(name){}
}val kotliner = Human("Kotliner", age: 26)
val angel = Human("Angel", age: 27)

Swift

然后:第一步,我教你先识别你的女神是不是单身, extension 就可以给 Human 添加一个是否单身的属性(计算性属性)

//note: Swift扩展只能是计算型属性,也必须使用var修饰,且不能赋值操作
extension Human {var isSingle: Bool {return lover == nil}
}
let angelIsSingle = angel.isSingle // true

你看, 恭喜 恭喜 ,女神还单身,你有机会是吧!

Kotlin

这TMD也可以啊,看我也现学现卖一下。是否单身的属性我们也可以加,就是写法不太一样;

fun Human.isSingle Boolean {return this.lover == null
}val angelIsSingle = angel.isSingle // true

Swift

哎呦不错哦,看样子Kotlin君天资聪慧,不久就可以脱单了;
再来:我看你女神比较高冷,试试使用撩妹秘籍,通过Extension,让Human学会一个陷入爱河的方法(func)
如果是你来撩的话

extension Human {func fallInLoveBy撩X秘籍(_ lover: Human) {self.lover = lover;}
}angel.fallInLoveBy撩X秘籍(kotliner)
let isSingle = angel.isSingle // false
let angelsLover = angel.lover?.name // Kotliner

看,你的女神不是单身了,而且爱上你了;

当然,只要你博爱,在Swift里甚至可以让全世界男女都爱上你

//note: 类方法扩展,未实例对象
extension Human {class func perfectLoversName() -> String {return "Kotliner"}
}
var name = Human.perfectLoversName() // Kotliner

Kotlin

这招狠啊,我也试试看看,有没有觉得我们的写法要更简洁点:

fun Human.fallInLoveBy撩X秘籍(lover: Human){this.lover = lover
}angel.fallInLoveBy撩X秘籍(kotliner)val isSingle = angel.isSingle // false
val angelsLover = angel.lover?.name // Kotliner

Swift

是啊,厉害厉害。

Kotlin

我还悟出了其他的撩妹技巧,你也看看你以前用过没有;

fun Human.壁咚(lover: Human){this.lover = nulllover = null
}kotliner.壁咚(angel)  //卒......

Swift

哈哈哈哈哈,强行壁咚的下场太可怕了,我们也一样只是换成nil,但这个扩展是同源的,和前面一样的。
我还有一招献上

Kotlin

霸王硬上弓?

Swift

那不是你卒,是你两全卒。
回正题,你知道以前我们父母他们那一辈有媒妁之约,男孩女孩一出生就婚定一生是吧!前面一大堆的扩展学习太麻烦都可以省去,我直接在你女神出生那一刻就给你定娃娃亲,这事就简单了;(构造器)

当你的女神还是一个baby的时候,订个娃娃亲就好简单了

// note: 构造器扩展只能用便利构造器 详见 《类与继承》 漫谈篇
extension Human {// 刚刚出生 age=0convenience init(birthWithName name: String, lover: Human?) {self.init(name, age: 0)self.lover = lover}
}
// Angelababy(感情你女神是杨颖啊)
var angelBaby = Human.init(birthWithName: "Angel", lover: kotliner)

哈哈哈,一下子就成了。

Kotlin

这个好,你们可以事后诸葛,但我们貌似是没法做构造器扩展的,倒是可以在创建类时添加一个的构造器:

class Human(name:String){...constructor(name:String ,lover: Human,age: Int = 0) : this(name){}
}
var angelBaby = Human(name = "Angel", lover = kotliner)

试了这么多方法有好有坏,都这么快就学会了,女神我算是已经追求到手了,我打算明天求婚。

Swift

等等等一下。。好不容易追到你女神,你要爱惜她 尊重她 安慰她 保护着她,俩人同心建立起美满的家庭。。。
你愿意这样做吗?

Kotlin

Yes, I do

Swift

好在你是程序员,物质基础比较牢靠,结婚后需要有一份稳定的工作做保证;

Kotlin

是是是,我这边公司加班太多了,以后都没法陪老婆孩子,想换一家工作时间分配比较合理一点的公司,你给我推荐一下吧;

Swift

好,这份我们公司的程序员工作合同,签了它就可以过来上班了

protocol DeveloperJobProtocol {var job:String { get }var salary: Int { get }var level: Int { get }var childSex: Sex { get }
}

签合同很简单,看我给你演示一下


enum Sex {case male, female
}extension Human: DeveloperJobProtocol {var job:String {return "Andriod"}var salary: Int {return level*2000 + 6000}var level: Int {return 6}var childSex: Sex {return .female}
}kotliner.salary // 18k

这是我们公司根据你的情况给你做的合同

Kotlin

18k,很好。知足了

enum class Sex {male,female
}val Human.job: String
get():String {return "Andriod"}
var Human.salary: Int
get():Int {return level*2000 + 6000}
var Human.level: Int
get():Int {return 6}
var Human.childSex: Sex
get():Int {return Sex.female}kotliner.salary // 18k

合同我签了,但 childSex 是什么鬼?

Swift

你做了程序员,那你不就注定生女儿了嘛。我都想象到未来你们生女儿一起生活的画面了!(扩展嵌套类型)

extension Human {class Child: Human {var sex:Sex = kotliner.childSexweak var father: Human? = kotlinerweak var mother: Human? = kotliner.lover}var daughter: Child {return Child.init("littleAngel", age: 0)}
}let yourChild = kotliner.daughter
let childFatherName = yourChild.father?.name // Kotliner

Kotlin

哇!!!当程序员居然有这个福利。我喜欢生女儿,生女儿好;可是为什么我女儿的父亲母亲要用weak

Swift

你傻啊,你女儿终有一天会嫁出去的,不用weak的话就和你循环引用释放不了,你还想留你女儿一辈子?但是Human的lover我没有加weak,就是故意让你们相互引用,相守一身不离不弃;

Kotlin

我。。。(感动ing)

Swift

好了好了,你先关注当下
婚礼的事情只欠东风,你这还没有结婚就有孩子了,明儿求婚还不是百分百搞定;

Kotlin

Swift君,多谢兄弟帮忙;婚礼的事情也希望请你多多指教,我没有经验;

Swift

其实都差不多了,就差一本结婚证,你们能够遵守婚姻协议后这事就成了

// 婚姻协议
protocol MarriageProtocol {var promise:String { get }var approveByGovernment: Bool {get}
}// 这协议的内容我已经限制人类身上了,动物结婚不需要政府允许的
extension MarriageProtocol where Self: Human {// 誓言承诺var promise: String {return "我愿意无论是顺境或逆境,富裕或贫穷,健康或疾病,快乐或忧愁,都将毫无保留地爱ta,对ta忠诚直到永远。无论是健康或疾病。贫穷或富有,无论是年轻漂亮还是容颜老去,我都始终愿意与ta,相亲相爱,相依相伴,相濡以沫,一生一世,不离不弃"}// 政府允许var approveByGovernment: Bool {return true}
}

剩下的你们遵守婚姻协议就好了

// 人类遵守了婚姻协议:1.履行承诺;2.政府认可
extension Human: MarriageProtocol {}let kotlinerPromise = kotliner.promise
let angelPromise = angel.promise
let angelAuthentic = kotliner.approveByGovernment // true
let kotlinerAuthentic = angel.approveByGovernment // true

好了,你们的婚姻都有政府见证,都有对方的誓言。恭喜你kotlin君,你脱单了

Kotlin

Swift君 ,我说不出话了。好兄弟无言表达我的谢意;

Swift

这没什么,我只是分享指导了我的撩妹技巧而已;

内心独白:

TMD,为啥我Swift君指导别人都能成功,自己单身狗当着都是偷偷摸摸的。不做ios了,我要转Android开发;脱单的可能不是考秘籍,而是靠Google爸爸啊

拓展 Extensions 知识点 ( Swift 篇 )

Swuft 扩展 就是为一个已有的类、结构体、枚举类型或者协议类型添加新功能。和OC的category类似
- 拓展语法
- 计算属性
- 构造器
- 方法
- 下标
- 嵌套类型
- 协议

拓展语法: 举几个常见的

class Human: NSObject {var name = "my_vc"init(name: String) {self.name}func work() {print("工作中")}
}extension Human {func drivingTest() {print("通过驾照考试")}
}extension Human: UITableViewDelegate, UITableViewDataSource {func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return 3;}func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {return UITableViewCell()}func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {print(name)}
}

计算型属性

// 基础类型
extension Double {var km: Double { return self / 1000.0 }var m : Double { return self }var cm: Double { return self * 100.0 }var mm: Double { return self * 1000.0 }
}
let distance = Double(7353)
distance.km// 结构体(class 类似)
struct iOSer {var name: String
}
extension iOSer {var isValid: Bool {return !name.isEmpty}mutating func work() {name = name + "_coding_dog"}
}// 枚举拓展
enum AppleDevice {case iPhone,iPod,iPad,Mac,iMac
}extension AppleDevice {func whatShouldIBuy(money: Int) -> AppleDevice {if money < 10000 {return .iPhone}return .Mac}
}

支持构造器

值类型可以直接构造,引用类型需要使用便利构造器

// 参考已有的如上代码:iOSer、Humanextension iOSer {init(firstName: String, secondName: String) {self.name = firstName + secondName}
}extension Human {convenience init(firstName: String, secondName: String) {self.init(name: firstName + secondName)}
}

方法

静态方法,实例方法,类方法

extension iOSer {static func bestPrictise() -> String {return "Swift3.1"}func favoriteLanguage() -> String {return "\(name) loved swift"}
}
let bp = iOSer.bestPrictise()
let xcodeyang = iOSer(name: "xy")
xcodeyang.favoriteLanguage()extension Human {static func tranlateChinese() -> String {return "人类"}class func tranlateJanpanese() -> String {return "ピープル"}func coding(code:(()->Void)?) {code?()}
}let chineseName = Human.tranlateChinese()
let janpaneseName = Human.tranlateJanpanese()
let me = Human(firstName: "yang", secondName: "zhi")
me.coding {print("Hello World")
}

嵌套类型

比如结构体里面的枚举等等


extension iOSer {class Job {var experience: Int = 0 {didSet{salary = experience>3 ? 50:10}}var salary = 0init(l: Language) {if l != .oc {experience = 3salary = 30}}}enum Language {case oc, swift, java, js, c}var myFavoriteDSL: Language {return .js}var newJob: Job {return Job(l: myFavoriteDSL)}
}xcodeyang.newJob.salary

下标

常见数组,字典等等


extension Int {subscript(digitIndex: Int) -> Int {var decimalBase = 1for _ in 0..<digitIndex {decimalBase *= 10}return (self / decimalBase) % 10}
}
746381295[0] // 7
746381295[5] // 1

扩展 && 协议

详细可以参考后面协议的部分

通过扩展遵循协议


protocol TextRepresentable {var textualDescription: String { get }
}struct Human {var name: Stringvar textualDescription: String {return "这个人叫\(name)"}
}extension Human: TextRepresentable {}let textProtocal: TextRepresentable = Human(name: "john")
textProtocal.textualDescription
// 或者
let human = Human(name: "john")
human.textualDescriptionprotocol PrettyTextRepresentable: TextRepresentable {var prettyTextualDescription: String { get }
}extension Human: PrettyTextRepresentable {var prettyTextualDescription: String {return name.isEmpty ? "❌: 人名无效" : "✅:这个人叫\(name)"}
}let john = Human(name: "john")
let unnamed = Human(name: "")
print(john.prettyTextualDescription)
print(unnamed.prettyTextualDescription)

通过扩展遵循协议实现协议的默认实现


protocol PlayGame {var gameName: String {get}func startGame()func endGame()
}extension PlayGame {func startGame() {print("\(self.gameName) 游戏开始了")}func endGame() {print(self.gameName + " 结束了")}
}extension Daniel: PlayGame {var gameName: String {return "王者荣耀"}
}human.gameName
human.startGame()
human.endGame()

为协议扩展添加限制条件


// 娱乐项目
protocol Entertainment {var name: String {get}func haveFun()
}extension Entertainment where Self: Programmer {var name: String {return "王者荣耀"}func haveFun() {print("开始玩\(name)啦。。")}
}extension Entertainment where Self: Producter {// 拓展里只能是计算属性var name: String {return "狼人杀"}func haveFun() {print("来一起玩\(name),怎么样")}
}class Programmer: Entertainment {}class Producter: Entertainment {}class Designer: Entertainment {func haveFun() {print("自己看看\(name)")}var name: String = "动画片"
}let prog = Programmer()
prog.haveFun()
let prod = Producter()
prod.haveFun()
let desi = Designer()
desi.haveFun()

集合的运用


extension Collection where Iterator.Element: Entertainment {var allNames:String {return self.reduce("结果:", {$0 + "\n" + $1.name})}
}let representableArray = [Designer(),Designer(),Designer()]
// 留下待解决问题
//let representableArray = [Programmer(),Designer()] as [Entertainment]
print(representableArray.allNames)

扩展 Extensions ( Kotlin 篇 )

在Kotlin中,允许对类进行扩展,不需要继承或使用 Decorator 模式,通过一种特殊形式的声明,来实现某一具体功能。扩展函数是静态解析的,并未对原类增添函数或者属性,也就是说对其本身没有丝毫影响。

扩展函数:

在kotlin里,通过扩展函数,我们可以很方便的为一个类添加一个方法。

fun String.lastChar(){this.get(this.length - 1)
}fun String.lastChar() = get(this.length - 1)

上面两种写法其实是一样的。其中,this关键字指代接收者对象(receiver object)(也就是调用扩展函数时, 在点号之前指定的对象实例),有时可以省略。

扩展函数的调用

以上面的函数为例

 "Android".lastChar()

扩展函数的声明格式:

fun receiverType.functionName(params){body
}

其中
- receiverType:表示函数的接收者,也就是函数扩展的对象
- functionName:扩展函数的名称
- params:扩展函数的参数,可以为NULL
- body 函数体

扩展函数是静态解析的

扩展方法是静态解析的,而并不是真正给类添加了这个方法。
调用的扩展函数是由函数调用所在的表达式的类型来决定的,而不是由表达式运行时求值结果决定的。

open class Animal{}
class Cat : Animal()object Main {fun Animal.food() = "food"fun Cat.food() = "fish"fun Animal.printFood(anim: Animal){println(anim.food())}@JvmStatic fun main(args: Array<String>) {Animal().printFood(Cat())}
}

最终的输出是 food ,而不是 fish 。
因为扩展方法是静态解析的,在添加扩展方法的时候类型为Animal,那么即便运行时传入了子类对象,也依旧会执行参数中声明时类型的方法。

成员函数和扩展函数

如果一个类定义有一个成员函数和一个扩展函数,而这两个函数又有相同的接收者类型、相同的名字并且都适用给定的参数,这种情况总是优先调用成员函数。

class Dog : Animal(){fun printFood(){println("meat")}
}object Main {fun Dog.printFood(){println("bone")}@JvmStatic fun main(args: Array<String>) {val dog: Dog = Dog()dog.printFood()}
}

这里输出 meat。

扩展属性

val TextView.leftMargin:Int
get():Int {return (layoutParams as ViewGroup.MarginLayoutParams).leftMargin}
set(value) {(layoutParams as ViewGroup.MarginLayoutParams).leftMargin=value}

由于扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的。所以,对于扩展属性不允许存在初始化器。 扩展属性的行为只能由显式提供的 getters/setters 定义。也就意味着扩展属性只能被声明为val而不能被声明为var.如果强制声明为var,即使进行了初始化,在运行也会报异常错误,提示该属性没有幕后字段。

伴生对象的扩展

如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数和属性:

fun Animal.Companion.eat() {println("eat")
}val Animal.Companion.food: String
get() = "food"@JvmStatic fun main(args: Array<String>) {println("food:${Animal.food}")Animal.eat()
}

对于伴生对象的扩展属性和方法,只需用类名作为限定符去调用他们就可以了。

扩展的作用域

我们在a包中定义的扩展方法

package afun Cat.food() { …… } 

要在a包之外使用这个扩展,我们需要在调用方导入它:

package b
import a.food // 导入所有名为“food”的扩展// 或者
import a.*   // 从“a包”导入一切fun usage(cat: Cat) {cat.food()

最后安利一下:一起聊聊 Kotlin 在 Android、JS、JVM(后端)、Native、DSL各个平台的技术实践与分享,关注此公众号,加入我们

Swift vs. Kotlin 漫谈之扩展篇相关推荐

  1. JetBrains开发者日见闻(一)之Kotlin/Native 尝鲜篇

    简述: 今天我们来讲点Kotlin中比较时髦的东西,有的人可能会说:"不像你之前的风格啊,之前的文章不是一直在死扣语法以及语法糖背后秘密.当你还在死扣泛型语法的时候,别人的文章早就说了Kot ...

  2. Kotlin之美——DSL篇 和 如何让你的回调更具Kotlin风味

    如何让你的回调更具Kotlin风味 https://mp.weixin.qq.com/s?__biz=MzAwOTQ4Mzk2Nw==&mid=2458585682&idx=1& ...

  3. Kotlin 第三讲——集合篇1

    内容简介:前文介绍了数据类型相关的文章,本讲我们来聊聊 Kotlin 中的集合. 简介 Kotlin 完全兼容 Java 的集合,且 Kotlin 有专有的集合:可变集合&不可变集合(本质还是 ...

  4. WEB攻击手段及防御-扩展篇

    转载自 WEB攻击手段及防御-扩展篇 之前的文章介绍了常见的XSS攻击.SQL注入.CSRF攻击等攻击方式和防御手段,没有看的去翻看之前的文章,这些都是针对代码或系统本身发生的攻击,另外还有一些攻击方 ...

  5. JDK8之新特性扩展篇

    转载自 JDK8之新特性扩展篇 BASE64 base64编码解码已经被加入到了jdk8中了. import java.nio.charset.StandardCharsets; import jav ...

  6. 从零开始学架构4 - 可扩展篇

    从零开始学架构4 - 可扩展篇 32 | 可扩展架构的基本思想和模式 今天我们进入架构可扩展模式的学习,这部分内容包括分层架构.SOA 架构.微服务和微内核等,先来聊聊架构的可扩展模式. 可扩展的基本 ...

  7. 软开关设计漫谈_软件篇

    //========================================================================   //TITLE:   //    软开关设计漫 ...

  8. 第12章 Spring AOP之扩展篇

    第12章 Spring AOP之扩展篇 本章内容 有关公开当前调用的代理对象的探讨 有关公开当前调用的代理对象的探讨 注:有关公开当前调用的代理对象的探讨这句话很机械,可以这么理解:把当前目标对象所依 ...

  9. 【系】微信小程序云开发实战坚果商城-扩展篇

    第 5-1 课:扩展篇 目录 开篇 [系]微信小程序云开发实战坚果商城-开篇 基础篇 [系]微信小程序云开发实战坚果商城-弹性盒子 [系]微信小程序云开发实战坚果商城-ES6 简单入门 [系]微信小程 ...

最新文章

  1. Apache Web服务器访问控制机制全解析
  2. omct问题之-webapps下多出的ROOT目录
  3. 云炬Android开发笔记 4单Activity界面架构设计与验证
  4. Windows平台RTMP直播推送集成简要说明
  5. 中国首个芯片大学最快于本月底在南京挂牌;​华为方舟编译器正式支持 C 语言;Ora2Pg v21.0 发布|极客头条
  6. Vue脚手架中添加favicon.ico图标失效问题
  7. Q132:PBRT-V3,BSSRDF(双向散射表面反射分布函数)(5.6.2章节、11.4章节)
  8. jQuery Mobile 移动开发中的日期插件Mobiscroll使用说明
  9. javah生成java头文件
  10. 基于Visual C++2010与windows SDK fo windows7开发windows7平台的tabletpc应用(1)-手写数学公式输入
  11. 智能证件照制作——基于人脸检测与自动人像分割轻松制作个人证件照(C++实现)
  12. 【第04题】给定 a 和 b,问 a 能否被 b 整除 | if 语句 和 条件运算符的应用
  13. 手机 CPU 架构类型了解
  14. nginx——反向代理,https加密证书,重定向
  15. 【基础】Linux 常用操作
  16. 小学期 异形:达达学长的生死逃亡
  17. moss部署学习入门及注意事项
  18. 「Adobe国际认证」设计小白必须了解的色彩理论,绝对干货满满
  19. 给出某一个日期,用SQL分别计算日、月、季度、年下的同比环比
  20. 海外社交媒体有哪些?如何做好海外社交媒体推广?

热门文章

  1. 关于宠物饮水机的问题与设计
  2. 21天python百度网盘_《21天学通Python》PDF 高清版百度网盘下载
  3. 字节跳动Go 语言面试会问哪些问题?
  4. LINUX防御ssh远程暴力破解
  5. 在maven中的pom.xml配置ojdbc报错
  6. 任务11 雷达与超声波感应灯(arduino程序)
  7. Python量化教程:量化风险
  8. HTTP协议报文基本格式
  9. 夕阳落山图(js 夕阳下山)
  10. vscode背景图片无法删除