我们在上一篇讨论中介绍了一些基本的由scalaz提供的typeclass。这些基本typeclass主要的作用是通过操作符来保证类型安全,也就是在前期编译时就由compiler来发现错误。在这篇讨论中我希望能按照scalaz的格式设计自己的typeclass并能使之融入scalaz库结构里去。
我们来设计一个NoneZero typeclass。这个NoneZero typeclass能确定目标类型值是否为空,如:
0.nonZero = false
3.nonZero = true
“”.nonZero = false
“value”.nonZero = true
List().nonZero = false
List(1,2,3).nonZero = true
首先是trait: (定义typeclass行为)
1 trait NonZero[A] { 
2   def nonZero(a: A): Boolean 
3 }
现在NonZero typeclass只有一项功能或行为,就是这个抽象函数NonZero:对任何类型A值a,返回Boolean结果。
为了方便使用NoneZero typeclass,我们在伴生对象里定义NonZero[A]的构建函数,这样我们就不需要每次都重新实现抽象行为函数nonZero了:
1 object NonZero { 
2     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] { 
3         def nonZero(a: A): Boolean = f(a) 
4     } 
5 }
只要我们提供一个f: A => Boolean函数就能用create来构建一个NonZero[A]实例。实际上这个f函数定义了类型A在NonZero tyoeclass中的具体行为。
下一步是注入操作方法:
1 class NonZeroOps[A](a: A)(implicit ev: NonZero[A]) { 
2     def isNonZero: Boolean = ev.nonZero(a) 
3 }
我们注入了一个操作方法isNonZero。注意:注入方法是针对所有类型A的,所以需要NonZero[A]作为参数。
跟着就是隐式作用域解析了(implicit resolution):
1 object ToNonZeroOps { 
2     implicit def toNonZeroOps[A](a: A)(implicit ev: NonZero[A]) = new NonZeroOps[A](a) 
3 }
这是一个隐式视域(implicit view):从类型A转换到NonZeroOps[A]。这样类型A就具备isNonZero这个操作方法了。
我们按scalaz惯例在object NonZero放一个默认隐式转换:
1 object NonZero { 
2     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] { 
3         def nonZero(a: A): Boolean = f(a) 
4     } 
5     implicit val intNZInstance: NonZero[Int] = create { 
6         case 0 => false 
7         case _ => true 
8      } 
9 }
注意我们在create参数里使用了partial function。
然后试试在Int类型上使用:
1 import ToNonZeroOps._ 
2  
3 10.isNonZero                                      //> res0: Boolean = true 
4 0.isNonZero                                       //> res1: Boolean = false 
5 2.isNonZero                                       //> res2: Boolean = true
不错,已经可以用了。再试试其它即兴类型:
 1 import ToNonZeroOps._ 
 2 implicit val stringNZInstance: NonZero[String] = NonZero.create { 
 3   case "" => false 
 4   case _ => true 
 5 }                                                 //> stringNZInstance  : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@ 
 6                                                   //| 1c655221 
 7 implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b } 
 8                                                   //> booleanNZInstance  : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$ 
 9                                                   //| [email protected] 
10  
11 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create { 
12     case Nil => false 
13     case _ => true 
14 }                                                 //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]] 
15  
16 "".isNonZero                                      //> res0: Boolean = false 
17 "not empty".isNonZero                             //> res1: Boolean = true 
18 true.isNonZero                                    //> res2: Boolean = true 
19 false.isNonZero                                   //> res3: Boolean = false 
20 List(1,2,3).isNonZero                             //> res4: Boolean = true 
21 List("a","b").isNonZero                           //> res5: Boolean = true 
22 List().isNonZero                                  //> res6: Boolean = false 
23  
24  
25  
26 10.isNonZero                                      //> res7: Boolean = true 
27 0.isNonZero                                       //> res8: Boolean = false 
28 2.isNonZero                                       //> res9: Boolean = true
我把完整的代码贴在下面吧,供大家练习参考:
 1 trait NonZero[A] { 
 2     def nonZero(a: A): Boolean 
 3 } 
 4 object NonZero { 
 5     def create[A](f: A => Boolean): NonZero[A] = new NonZero[A] { 
 6         def nonZero(a: A): Boolean = f(a) 
 7     } 
 8     implicit val intNZInstance: NonZero[Int] = create { 
 9         case 0 => false 
10         case _ => true 
11      } 
12 } 
13 class NonZeroOps[A](a: A)(implicit ev: NonZero[A]) { 
14     def isNonZero: Boolean = ev.nonZero(a) 
15 } 
16 object ToNonZeroOps { 
17     implicit def toNonZeroOps[A](a: A)(implicit ev: NonZero[A]) = new NonZeroOps[A](a) 
18 } 
19  
20 import ToNonZeroOps._ 
21 implicit val stringNZInstance: NonZero[String] = NonZero.create { 
22   case "" => false 
23   case _ => true 
24 }                                                 //> stringNZInstance  : scalaz.ex5.NonZero[String] = scalaz.ex5$NonZero$$anon$1@ 
25                                                   //| 1c655221 
26 implicit val booleanNZInstance: NonZero[Boolean] = NonZero.create { b => b } 
27                                                   //> booleanNZInstance  : scalaz.ex5.NonZero[Boolean] = scalaz.ex5$NonZero$$anon$ 
28                                                   //| [email protected] 
29  
30 implicit def listNZInstance[A]: NonZero[List[A]] = NonZero.create { 
31     case Nil => false 
32     case _ => true 
33 }                                                 //> listNZInstance: [A]=> scalaz.ex5.NonZero[List[A]] 
34  
35 "".isNonZero                                      //> res0: Boolean = false 
36 "not empty".isNonZero                             //> res1: Boolean = true 
37 true.isNonZero                                    //> res2: Boolean = true 
38 false.isNonZero                                   //> res3: Boolean = false 
39 List(1,2,3).isNonZero                             //> res4: Boolean = true 
40 List("a","b").isNonZero                           //> res5: Boolean = true 
41 List().isNonZero                                  //> res6: Boolean = false 
42  
43  
44  
45 10.isNonZero                                      //> res7: Boolean = true 
46 0.isNonZero                                       //> res8: Boolean = false 
47 2.isNonZero                                       //> res9: Boolean = true
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/12941.html
