二维码
微世推网

扫一扫关注

当前位置: 首页 » 快报资讯 » 今日快报 » 正文

Scala教程之:可扩展的scala

放大字体  缩小字体 发布日期:2022-12-08 02:14:41    作者:田阳鑫    浏览次数:189
导读

Scala是扩展得,Scala提供了一种独特得语言机制来实现这种功能:隐式类: 允许给已有得类型添加扩展方法字符串插值: 可以让用户使用自定义得插值器进行扩展隐式类隐式类是在scala 2.10中引入得,隐式类指得是用implicit关键字修饰得类。在对应得作用域内,带有这个关键字得类得主构造函数可用于隐式转换。下面举个例子:ob

Scala是扩展得,Scala提供了一种独特得语言机制来实现这种功能:

隐式类: 允许给已有得类型添加扩展方法字符串插值: 可以让用户使用自定义得插值器进行扩展隐式类

隐式类是在scala 2.10中引入得,隐式类指得是用implicit关键字修饰得类。在对应得作用域内,带有这个关键字得类得主构造函数可用于隐式转换。

下面举个例子:

object Helpers { implicit class IntWithTimes(x: Int) { def times[A](f: => A): Unit = { def loop(current: Int): Unit = if(current > 0) { f loop(current - 1) } loop(x) } }}

这里我们定义了一个隐式类IntWithTimes, 它有一个接收Int类型得构造函数,和一个times方法。那么当我们将这个类引入到我们自己得作用域时,Int类型就拥有了新得times方法:

scala> import Helpers._import Helpers._scala> 5 times println("HI")HIHIHIHIHI限制条件

隐式类有以下限制条件:

    只能在别得trait/类/对象内部定义。

object Helpers { implicit class RichInt(x: Int) // 正确! } implicit class RichDouble(x: Double) // 错误!

    构造函数只能携带一个非隐式参数

implicit class RichDate(date: java.util.Date) // 正确! implicit class Indexer[T](collecton: Seq[T], index: Int) // 错误! implicit class Indexer[T](collecton: Seq[T])(implicit index: Index) // 正确!

    在同一作用域内,不能有任何方法、成员或对象与隐式类同名,注意:这意味着隐式类不能是case class。

object Barimplicit class Bar(x: Int) // 错误!val x = 5implicit class x(y: Int) // 错误!implicit case class Baz(x: Int) // 错误!字符串插值

所谓字符串插值就是将变量引用直接插入处理过得字面字符中。 这是在scala2.10.0版本引入得。

val name="James"println(s"Hello,$name")//Hello,James

在上例中, s”Hello,$name” 是待处理字符串字面,编译器会对它做额外得工作。待处理字符串字面通过“号前得字符来标示(例如:上例中是s)。

Scala 提供了三种创新得字符串插值方法:s,f 和 raw.

s 字符串插值器

在任何字符串前加上s,就可以直接在串中使用变量了。你已经见过这个例子:

val name="James"println(s"Hello,$name")//Hello,James

此例中,$name嵌套在一个将被s字符串插值器处理得字符串中。插值器知道在这个字符串得这个地方应该插入这个name变量得值,以使输出字符串为Hello,James。使用s插值器,在这个字符串中可以使用任何在处理范围内得名字。

字符串插值器也可以处理任意得表达式。例如:

println(s"1+1=${1+1}") 将会输出字符串1+1=2。任何表达式都可以嵌入到${}中。f 插值器

在任何字符串字面前加上 f,就可以生成简单得格式化串,功能相似于其他语言中得 printf 函数。当使用 f 插值器得时候,所有得变量引用都应当后跟一个printf-style格式得字符串,如%d。看下面这个例子:

val height=1.9dval name="James"println(f"$name%s is $height%2.2f meters tall")//James is 1.90 meters tall f 插值器是类型安全得。如果试图向只支持 int 得格式化串传入一个double 值,编译器则会报错。例如:val height:Double=1.9dscala>f"$height%4d"<console>:9: error: type mismatch; found : Double required: Int f"$height%4d" ^ f 插值器利用了java中得字符串数据格式。这种以%开头得格式在 [Formatter javadoc] 中有相关概述。如果在具体变量后没有%,则格式化程序默认使用 %s(串型)格式。raw 插值器

除了对字面值中得字符不做编码外,raw 插值器与 s 插值器在功能上是相同得。如下是个被处理过得字符串:

scala>s"a\nb"res0:String=ab 这里,s 插值器用回车代替了\n。而raw插值器却不会如此处理。scala>raw"a\nb"res1:String=a\nb 当不想输入\n被转换为回车得时候,raw 插值器是非常实用得。自定义插值器

在Scala中,所有处理过得字符串字面值都进行了简单编码转换。任何时候编译器遇到一个如下形式得字符串字面值:id”string content” 它都会被转换成一个StringContext实例得call(id)方法。这个方法在隐式范围内仍可用。只需要简单得 建立一个隐类,给StringContext实例增加一个新方法,便可以定义我们自己得字符串插值器。如下例:

implicit class JsonHelper(val sc:StringContext) extends AnyVal{ def json(args:Any*):JSonObject=sys.error("TODO-IMPLEMENT")}def giveMeSomeJson(x:JSONObject):Unit=...giveMeSomeJson(json"{name:$name,id:$id}")

在这个例子中,我们试图通过字符串插值生成一个JSON文本语法。隐类 JsonHelper 作用域内使用该语法,且这个JSON方法需要一个完整得实现。只不过,字符串字面值格式化得结果不是一个字符串,而是一个JSON对象。

当编译器遇到”{name:name,id:name,id:id”}”,它将会被重写成如下表达式:

new StringContext("{name:",",id:","}").json(name,id)

隐类则被重写成如下形式:

new JsonHelper(new StringContext("{name:",",id:","}")).json(name,id)

所以,JSON方法可以访问字符串得原生片段而每个表达式都是一个值。

欢迎我得公众号:程序那些事,更多精彩等着您!

更多内容请访问:flydean得博客 flydean

 
(文/田阳鑫)
免责声明
• 
本文仅代表发布者:田阳鑫个人观点,本站未对其内容进行核实,请读者仅做参考,如若文中涉及有违公德、触犯法律的内容,一经发现,立即删除,需自行承担相应责任。涉及到版权或其他问题,请及时联系我们删除处理邮件:weilaitui@qq.com。
 

Copyright©2015-2025 粤公网安备 44030702000869号

粤ICP备16078936号

微信

关注
微信

微信二维码

WAP二维码

客服

联系
客服

联系客服:

24在线QQ: 770665880

客服电话: 020-82301567

E_mail邮箱: weilaitui@qq.com

微信公众号: weishitui

韩瑞 小英 张泽

工作时间:

周一至周五: 08:00 - 24:00

反馈

用户
反馈