掀开Scala的糖衣(9) -- function composition 发表于 2013-12-30 Disqus: 本文字数: 1.5k 阅读时长 ≈ 1 分钟 Function composition,顾名思义,就是函数的组合。直接举例: 123def sayHi(name: String) = "Hi, " + namedef sayBye(str: String) = str + ", bye" 两个方法,一个说你好,一个说再见。然后我们创建很多个人名: 1val names = List("world", "tom", "xiao ming") 我们希望对List中的每个人都说你好然后说再见: 1names.map(sayHi).map(sayBye) 阅读全文 »
揭开Scala的糖衣(8) -- pattern matching 发表于 2013-12-29 Disqus: 本文字数: 3k 阅读时长 ≈ 3 分钟 Pattern matching是Scala中很好用的一个语言特性。先举一个最简单的例子: 1234567val number = 1number match { case 1 => doSomething() case 2 => doSomethingElse() case _ => doDefault()} 这个代码和我们熟悉的switch case看起来很像,其实,这段代码反编译之后和Java的switch case确实就是一样的: 1234567891011int number = 1;int i = number; switch (i){default: doDefault(); break;case 2: doSomethingElse(); break;case 1: doSomething();} 但是和Java的switch case不一样的是,Scala的pattern matching作为一个expression是可以evaluate一个值出来的,我们把上面的代码改一下,让doSomething,doSomethingElse和doDefault都返回点东西: 1234567val number = 1val result = number match { case 1 => doSomething() case 2 => doSomethingElse() case _ => doDefault()} 阅读全文 »
剥掉Scala的糖衣(7) -- apply method 发表于 2013-12-29 Disqus: 本文字数: 1.4k 阅读时长 ≈ 1 分钟 apply method是一个很简单的语言特性。如果一个class或者是object有一个主要的方法,那么与其每次显式的调用这个主要的方法,还不如隐式调用。举个例子: 123456class Kettle { def boil(water: Water) = { water.isWarm = true water }} 一个水壶的主要作用就是烧开水,于是我们每次都要调用boil方法来烧开水: 12val kettle: Kettle = new Kettle()kettle.boil(new Water()) 如果要把它改写成apply method的方式,只需要给boil改个名字就好了: 123456class Kettle { def apply(water: Water) = { water.isWarm = true water }} 阅读全文 »
褪去Scala的糖衣(6) -- partial application 发表于 2013-12-25 Disqus: 本文字数: 2k 阅读时长 ≈ 2 分钟 这篇博客介绍一下Scala中的partial application,局部应用,或者叫做柯里化。 所谓柯里化就是指把一个接受多个参数的函数的一部分参数写死,剩下的一部分由调用者提供。 用Java代码来表述,大概可以写成这样: 1234567891011public String greet(String greeting, String name) { return greeting + " " + name;}public String sayHello(String name) { return greet("Hello", name);}public String greetXiaoMing(String greeting) { return greet(greeting, "Xiao Ming");} greet用来给某个不确定的人打个不确定的招呼。 sayHello用来给某个不确定的人说一句固定的Hello。 阅读全文 »
剥开Scala的糖衣(5) -- lazy 发表于 2013-12-24 Disqus: 本文字数: 1k 阅读时长 ≈ 1 分钟 Scala中的lazy关键字是实现延迟加载的好帮手。 在Java中想要做到延迟加载,常规的做法是大抵是这样的: 12345678private String str = null;public String getStr() { if (str == null) { str = getStrFromWebService(); } return str;} 以这种方式来保证web service不会被无谓的重复请求。 C#中则可以使用Lazy of T来实现类似的事: 123456789private Lazy<String> str = new Lazy<string> (() => GetStrFromWebService ());public String Str{ get { return str.Value; }} 阅读全文 »
去掉Scala的糖衣(4) -- type aliase 发表于 2013-12-23 Disqus: 本文字数: 3.3k 阅读时长 ≈ 3 分钟 Scala中有一个type关键字,用来给类型或者是操作起别名,用起来很是方便。 比如这样: 1type People = List[Person] 这样就是给List[Person](方括号是Scala的类型参数的写法)声明了一个别名,叫做People。 接下来就可以这样使用它: 123def teenagers(people: People): People = { people.filter(person => person.age < 20)} 阅读全文 »
Scala中的语言特性是如何实现的(3) -- trait 发表于 2013-10-13 Disqus: 本文字数: 4.8k 阅读时长 ≈ 4 分钟 我在Coursera上跟了一门叫做Functional Programming Principles in Scala的课程,是由Scala的作者Martin Odersky讲授的。其中第三周的作业中使用到了Scala的trait这个语言特性。 我以前熟知的语言都没有类似的特性(Ruby的mixin和Scala的trait很像,但是Ruby我不熟),所以这周的博客就分析一下这个语言特性是如何实现的。 trait在讲trait的实现机制之前,先看一个使用trait的例子。假设我们有以下几个类: 123456789101112131415161718192021222324252627abstract class Plant { def photosynthesis = println("Oh, the sunlight!")}class Rose extends Plant { def smell = println("Good!") def makePeopleHappy = println("People like me")}class Ruderal extends Plant { def grow = println("I take up all the space!")}abstract class Animal { def move = println("I can move!")}class Dog extends Animal { def bark = println("Woof!") def makePeopleHappy = println("People like me")}class Snake extends Animal { def bite = println("I am poisonous!")} 植物家族有玫瑰和杂草。 阅读全文 »
为什么必须是final的呢? 发表于 2013-06-22 Disqus: 本文字数: 3.5k 阅读时长 ≈ 3 分钟 一个谜团如果你用过类似guava这种“伪函数式编程”风格的library的话,那下面这种风格的代码对你来说应该不陌生: 123456789public void tryUsingGuava() { final int expectedLength = 4; Iterables.filter(Lists.newArrayList("123", "1234"), new Predicate<String>() { @Override public boolean apply(String str) { return str.length() == expectedLength; } });} 这段代码对一个字符串的list进行过滤,从中找出长度为4的字符串。看起来很是平常,没什么特别的。 但是,声明expectedLength时用的那个final看起来有点扎眼,把它去掉试试: error: local variable expectedLength is accessed from within inner class; needs to be declared final 阅读全文 »
Scala中的语言特性是如何实现的(2) 发表于 2013-05-11 Disqus: 本文字数: 3.3k 阅读时长 ≈ 3 分钟 上篇博文的末尾留了三个问题,现在自问自答一下。 在Scala中被声明为val的v4为什么在反编译的Java中不是final的呢?在方法中声明局部变量时,如果用Scala的val关键字(或者是Java中的final)来修饰变量,则代表着此变量在赋过初始值之后不可以再被重新赋值。这个val或者final只是给编译器用的,编译器如果发现你给此变量重新赋值会抛出错误。 而bytecode不具备表达一个局部变量是immutable的能力,也就是说对于JVM来说,不存在不可变的局部变量这个概念。所以v4在反编译之后,就和普通的局部变量无异了。 在Scala中被声明为val的v2为什么在反编译的C#中不是readonly的呢?这是个挺tricky的问题,我试着解释一下。Scala .NET是基于IKVM实现的,IKVM可以把Java bytecode翻译为CIL。所以Scala编译为CIL的过程实际是这样的: 阅读全文 »
Scala中的语言特性是如何实现的(1) 发表于 2013-05-05 Disqus: 本文字数: 3.3k 阅读时长 ≈ 3 分钟 Scala可以编译为Java bytecode和CIL,从而在JVM和CLI之上运行。Scala有很多在Java和C#的世界中显得陌生的语言特性,本文将分析这些语言特性是如何实现的。 objectScala中可以像这样创建object: 12345object HowIsObjectImplementedInScala { def printSomething() { println("printSomething") }} 然后在代码的其他地方调用printSomething,一个object究竟是什么东西呢?我们将这段Scala编译为Java bytecode,然后反编译为Java,会发现编译器为HowIsObjectImplementedInScala这个object生成了两个类: 123456789101112131415161718192021222324252627public final class HowIsObjectImplementedInScala{ public static void printSomething() { HowIsObjectImplementedInScala..MODULE$.printSomething(); }}public final class HowIsObjectImplementedInScala${ public static final MODULE$; static { new (); } public void printSomething() { Predef..MODULE$.println("printSomething"); } private HowIsObjectImplementedInScala$() { MODULE$ = this; }} 阅读全文 »
如何一步一步推导出Y Combinator 发表于 2013-04-09 Disqus: 本文字数: 2.8k 阅读时长 ≈ 3 分钟 本文讲什么?本文用Scheme(Racket)代码为例,一步一步的推出Y Combinator的实现。 本文不讲什么?Y Combinator是什么,干什么用的,它为什么能够work,它的数学含义以及实际应用场景,这些话题由于篇幅所限(咳咳,楼主的无知)不在本文论述范围之内。 如果有兴趣,请参考维基: http://en.wikipedia.org/wiki/Fixed-point_combinator#Y_combinator 鸣谢 阅读全文 »
用豆瓣读书Chrome插件,简单购买电子书 发表于 2013-04-01 Disqus: 本文字数: 880 阅读时长 ≈ 1 分钟 为什么要做这款插件?在豆瓣上查看一本书的时候,页面的右侧会显示哪些网站可以购买该书以及各自的价格。比如这本《乡关何处》,页面右侧显示了亚马逊,京东,当当等网站的购买链接。 但是豆瓣只会提供纸质书的购买链接,不提供电子书的。除非该书豆瓣自己有售。所以我写了个Chrome的插件来解决这个问题。 这款插件怎么用?这款插件会在每个图书页面上添加正版电子书的购买链接及其价格。您只需点击链接去购买就好了。 阅读全文 »
测试 发表于 2013-03-04 Disqus: 本文字数: 42 阅读时长 ≈ 1 分钟 测试发布文章 测试修改 再次修改 好久没用了,还能更新吗?test is it fixed 10? 阅读全文 »
自己动手重新实现LINQ to Objects 12 - DefaultIfEmpty 发表于 2012-04-10 Disqus: 本文字数: 3.4k 阅读时长 ≈ 3 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/29/reimplementing-linq-to-objects-part-12-defaultifempty.aspx 上次实现 First / Last的时候写了大量的代码,相比起来,今天要讲的 DefaultIfEmpty 就轻松多了。 DefaultIfEmpty是什么?这个操作符虽然简单,但是还是有 两个重载 : 阅读全文 »
自己动手重新实现LINQ to Objects 11 - First,Last,Single以及它们带有OrDefault的重载 发表于 2012-04-09 Disqus: 本文字数: 10k 阅读时长 ≈ 9 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/29/reimplementing-linq-to-objects-part-11-first-single-last-and-the-ordefault-versions.aspx 今天我实现了六个操作符,每个操作符都有两个重载。我一开始以为这些操作符的实现会很相似,但是最后发现每个都稍微有些不同… 今天实现了哪些操作符? 以下三个集合的排列 {First, Last, Single}, { 带有 / 不带有 OrDefault }, { 带有 / 不带有谓词} ,其结果是十二个不同的方法签名: 阅读全文 »
自己动手重新实现LINQ to Objects 10 - Any和All 发表于 2012-02-15 Disqus: 本文字数: 3.7k 阅读时长 ≈ 3 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/28/reimplementing-linq-to-objects-part-10-any-and-all.aspx 今天我们介绍两个操作符:Any 和 All。 Any 和 All做什么? Any 有两个重载,而 All只有一个: 阅读全文 »
自己动手重新实现LINQ to Objects 9 - SelectMany 发表于 2011-12-15 Disqus: 本文字数: 7.3k 阅读时长 ≈ 7 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/27/reimplementing-linq-to-objects-part-9-selectmany.aspx 我们接下来要实现的这个操作符是LINQ 中最重要的操作符。大多数(或者是全部?)其他的返回一个序列的操作符都可以通过调用 SelectMany来实现,这是后话按下不表。现在我们首先来实现它吧。 SelectMany 是什么? SelectMany 有四个重载,看起来一个比一个吓人: 阅读全文 »
自己动手重新实现LINQ to Objects 8 - Concat 发表于 2011-09-14 Disqus: 本文字数: 4.5k 阅读时长 ≈ 4 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/27/reimplementing-linq-to-objects-part-8-concat.aspx 上文讲的 Count 和 LongCount 返回的是数值类型,本文我们讲的 Concat 返回的是一个序列。 Concat 是什么? Concat 只有一种签名形式,这让它使用起来很简单: 阅读全文 »
自己动手重新实现LINQ to Objects 7 - Count和LongCount 发表于 2011-09-05 Disqus: 本文字数: 5.2k 阅读时长 ≈ 5 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/26/reimplementing-linq-to-objects-part-7-count-and-longcount.aspx 今天的文章要介绍两个 LINQ 操作符,因为它们实在是太类似了,所以放到一起来讲。 Count 和 LongCount的实现非常相像,不同的只是方法名,返回值类型和几个变量。 Count 和 LongCount 是什么呢? Count 和 LongCount各自有两个重载:一个重载接受谓词,另一个不接受。下面是这四个方法的签名: 1234567public static int Count < TSource > (this IEnumerable < TSource > source)public static int Count < TSource > (this IEnumerable < TSource > source, Func < TSource, bool > predicate)public static long LongCount < TSource > (this IEnumerable < TSource > source)public static long LongCount < TSource > (this IEnumerable < TSource > source, Func < TSource, bool > predicate) 阅读全文 »
浅析延迟执行--实现,优点,陷阱以及题外话 发表于 2011-08-31 Disqus: 本文字数: 206 阅读时长 ≈ 1 分钟 上周五在公司内部做了一个小型的sharing,讨论了一些与延迟执行有关的东西。现在把ppt和代码分享出来。如有谬误,请不吝指教 :) 代码在这儿: http://codeformyblog.codeplex.com/SourceControl/changeset/view/62764#1095173 ppt在这儿: Deferred execution View more presentations from cuipengfei 阅读全文 »
自己动手重新实现LINQ to Objects 6 - Repeat 发表于 2011-08-24 Disqus: 本文字数: 1.2k 阅读时长 ≈ 1 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/24/reimplementing-linq-to-objects-part-6-repeat.aspx本文的主题是个无关紧要的方法, Repeat 。关于 Repeat ,值得讨论的内容比 Empty还要少。写这篇博文只是为了保证这个系列的完整性。 Repeat 是什么? Repeat 是一个静态的泛型方法,不是扩展方法,它只有一个签名形式: 1public static IEnumerable<TResult> Repeat<TResult>(TResult element,int count) 它返回一个序列,该序列中反复的包含“ count ”个指定的元素,。 Repeat 只需要一个参数校验:检验“ count ”不是负数。 阅读全文 »
自己动手重新实现LINQ to Objects 5 - Empty 发表于 2011-08-23 Disqus: 本文字数: 3.3k 阅读时长 ≈ 3 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/24/reimplementing-linq-to-objects-part-5-empty.aspx这一篇继续讲非扩展方法。这次我们要讲的是 Empty ,它有可能是最简单的 LINQ 操作符了。 Empty 是什么? Empty 是一个泛型的,静态的方法,它只有一个签名形式,不接受任何参数: public static IEnumerable Empty() 阅读全文 »
自己动手重新实现LINQ to Objects 4 - Range 发表于 2011-08-22 Disqus: 本文字数: 3.8k 阅读时长 ≈ 3 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/24/reimplementing-linq-to-objects-part-4-range.aspx 本篇博文较短,接下来的几篇估计也会比较短。我觉得只有 很相似的几个 LINQ 操作符才适合放到同一篇博文里面,比如 Count 和LongCount 就比较适合放在一起讲。不过我也要采纳读者的意见,如果你喜欢“肥胖”一点的博文的话,请留言说明。 本文将要讲解 Range 操作符。 Range 操作符是什么? 阅读全文 »
自己动手重新实现LINQ to Objects 3 - Select 发表于 2011-08-22 Disqus: 本文字数: 3.5k 阅读时长 ≈ 3 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/12/23/reimplementing-linq-to-objects-part-3-quot-select-quot-and-a-rename.aspx 距离上次写完本系列博文的 第一篇 和 第二篇 已经有一段日子了,希望接下来的进度会快一些。 现在我给本项目在 Google Code 上建立了源码管理 ,现在就无需每篇博文包含一个 zip 文件了。创建项目时,我给它取了个显而易见的名字,叫做 Edulinq 。我修改了代码中的命名空间,而且现在 这一系列博文的 tag 也修改为了Edulinq 了。好了,闲话少叙 … 我们来开始重新实现 LINQ 吧,这次要实现 Select 操作符。 Select 操作符是什么? 阅读全文 »
自己动手重新实现LINQ to Objects 2 - Where 发表于 2011-08-21 Disqus: 本文字数: 7.7k 阅读时长 ≈ 7 分钟 本文翻译自 Jon Skeet 的系列博文”Edulinq”。 本篇原文地址: http://msmvps.com/blogs/jon_skeet/archive/2010/09/03/reimplementing-linq-to-objects-part-2-quot-where-quot.aspx 提示:本篇文章较长。虽然我选择了一个比较简单的操作符来在本文中实现,不过我们还是会遇到一些特例以及一些与 LINQ相关的原则。因为我还在试着找出表现本文内容的最佳方式,所以本文的排版方式暂时是实验性的。 我们将要实现“ Where ”子句(也可以说是方法或操作符)。 Where 在总体上来说比较容易理解,但是涉及到延迟执行和流式处理的部分会有些麻烦。Where 方法是泛型的,不过只有一个类型参数(在我看来这很重要,因为我觉得一个方法的泛型参数越多就越令人难以理解)。哦,对了,我们将在本文开始涉及查询表达式,这算是本文的一点额外猛料。 Where 是什么? 阅读全文 »