打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
不一样的go语言-玩转语法之二

  本文继续玩转语法,是为之二。

  I/O(Input/Output),输入输出是计算机最为突出的特点,也可以说是计算机最为核心的功能。没有I/O,计算机就是一堆废铜废铁。从最低层的电子元器件开始,计算机科学家与工程师们,就一直奔跑在追求卓越的I/O性能的道路上。计算机每一次大跨越,就是一次I/O的脱胎换骨。从机械时代到电子管,到晶体管,再到集成电路,再到未来的量子时代,无不预示着I/O对于计算机科学的重要性。但这只是最基础的I/O层,在这之上,又有更多层次抽象,比如内存、磁盘、网络;更多的I/O表现形式,比如文件、数据库、键鼠、显示器、打印机等等。“一切皆是文件”,这是Unix/Linux的基本哲学之一,从这个角度看,即一切皆I/O。

  底层设计是如此,那么在高层设计,仍然是如此。从各个语言对于I/O的实现来看,无不将I/O置于重中之重的地方,从I/O的设计中,可大致看出一个语言的设计哲学与理念。比如java中有大量的类名包含stream,强调流的概念;而golang则没有出现这个词,更强调的是byte,即字节。从所有即文件的角度来看,字节更直观地对应到文件中的内容。而java则又进行了一次抽象,相当于将很多的字节看作是连续的字节流,同时对流提供了更多的操作方法,如flip、mark等。

  在Java中,I/O相关的SDK使用了大量的装饰器与适配器模式。装饰器模式其实是对原有类作功能增强的一种方法,而适配器则是将非同类型的东西变为同类型的东西。比如StringReader即是适配器类,它实现了流对象接口Reader。它的功能是将非流对象String适配为流对象。旧版SDK还有一个叫StringInputStream的类,它也是适配器类。适配器与装饰器详解如下:

|项|用途|参与对象|jdk示例|
|:—|:—|:—|
|装饰器|功能增强|两个或以上相同类型的类|BufferedInputStream, 可用于装饰其他的InputStream子类|
|适配器|类型转换(适配)|两个不同类型的类|StringReader, 将String转换(适配)为Reader类型|

  而在go语言中,I/O也大量采用这样的设计方式。比如:

相关类示例
装饰器MultiReader, MultiWriter, bufio.Reader, bufio.Writer, bufio.Scanner, LimitReader, TeeReader-
适配器string.Reader, bytes.Readerex: strings.NewReader(“test”)

  装饰器与适配器的使用,使得go库的设计大为简化,并且因此而产生无比的灵活性与扩展性,开发者可以自行设计新的装饰器、适配器完成开发任务。

  那么,在实际的开发过程中,装饰器与适配器还有哪些妙用呢?在前面讲述的例子中,这两者是应用在interface与struct的层面,其实在go语言中,两者更妙的应用是与func的结合,可以带来新鲜、意想不到的体验。比如:

package mainimport "fmt"func greet(name string) {	fmt.Printf("Hello %s!\n", name)}func decorateGreet(f func(string), name string) {	fmt.Println("before greet")	f(name)	fmt.Println("after greet")}func main() {	decorateGreet(greet, "John")}

  虽然这个例子有点丑陋,但这真的是装饰器的应用。尽管java的经验告诉我们,面向切面编程使用的应该是代理模式(静态代理或者动态代理),甚至要动用反射、ASM,但其实使用装饰器更直接。当然为了装一下逼,通常不会写上面那么直白的代码。

package mainimport "fmt"func greet(name string) {	fmt.Printf("Hello %s!\n", name)}func decorateGreet(f func(string)) func(string) {	return func(name string) {		fmt.Println("before greet")		f(name)		fmt.Println("after greet")	}}func main() {	decorateGreet(greet)("装逼John")}

  调用方式变了一下,档次一下升高了不知多少。这样看起来才能让人相信:我真的是在用装饰器。很显然,装饰器起到一个功能增强的作用,从代码上看,无非就是接受A类型的对象(函数也是对象),然后返回A类型的对象,而在返回类型的实现中触发入参,同时加一些功能增强的代码。

  对于适配器来说,使用它想当于做了一次类型强转,如下面的示例尝试将hi函数适配成greet函数。

package mainimport "fmt"type hi func()type greet func(string)func sayHi() {	fmt.Printf("Hi")}func toGreet(h hi) greet {	return func(name string) {		h()		fmt.Printf(", %s", name)	}}func main() {	toGreet(sayHi)("John")}

  当函数是一等公民的时候,一切看起来都是那么地自然顺畅,而类似的功能用java来实现,就必须提高到类的层面了。

欢迎关注个人公众号:不一样的go语言

来源:https://www.icode9.com/content-4-287551.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
如何使用 Go 中的函数类型 (function types)?
从小案例学习Go语言
go语言学习笔记 | Golang中文社区(Go语言构建) | Go语言中文网 | Go语言学习园地
Go语言字符串
Go语言的fmt包中文教程
Golang 新手可能会踩的 50 个坑
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服