锁定老帖子 主题:隐式转换:比动态类型更强大?
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-09-16
Implicit Conversions: More Powerful than Dynamic Typing?,我只对其中一部分进行了翻译。
本文内容主要来自隐式转换是[url=Haskell type classes]Scala[/url]中实现的一种类似于Haskell type classes的类型系统,它使得Scala这种静态类型的语言具有某些“动态”的特性。下面用具体例子来说明。 案例1:给String添加一个reduce方法,其返回值为字符串中大写字母组成的新字符串。 在Scala中,最终效果如下: //Scala val acronym = "Microsoft Certified Systems Engineer".reduce println(acronym) // MCSE 由于String是Java语言内置的类型,现在遇到的问题是:在静态语言中,我们不能在运行时往已经存在的类中动态添加方法。 在Scala中,我们可以定义一个新的类型,使它具有所需要的方法,然后再顶一个一个从已有类型到新类型的隐式转换。然后Scala编译器将会在幕后实施其魔法。代码如下: class MyStr(str:String) { def reduce = str.foldLeft(""){ (s,c) => if(c.isUpperCase) s+c else s } } implicit def str2MyStr(str:String) = new MyStr(str) 作为对照,我们看看在Ruby中的实现: class String def reduce arr = unpack('c*').select { |c| (65..90).include? c } arr.pack 'c*' end end puts 'HyperText Transfer Protocol'.reduce # HTTP 案例2:一个稍微复杂一点的问题:重载整数类型的<操作符,使得它能与String比较,并且但String的长度小于该整数时返回true,否则返回false 在Scala中,同样可以通过隐式转换机制来解决该问题。这一次我们使用比上面更简洁的形式: //Scala,that's all implicit def lessThanOverload(i: Int) = new { def <(str: String) = str.length < i } 下面我们看看Ruby中如何解决这个问题,一个很自然的想法是玩Fixnum中添加所需的方法: class Fixnum def <(str) str.size < self end end 很不幸的是,这个看起来很对的方法是行不通的。每次调用整数的<操作符时都会进入一个死循环并很快导致堆栈溢出。 我们可以将方法改写成如下以避免这个问题: class Fixnum def <(str) self >= str.size end end 这次不用担心堆栈溢出了,但新的问题出现了: 引用 irb(main):006:0> 123 < 'test'
=> true irb(main):007:0> 123 < 123 => true 这个问题的最终Ruby解法是这样的: class Fixnum alias_method :__old_less_than__, '<'.to_sym def <(target) if target.kind_of? String __old_less_than__ target.size else __old_less_than__ target end end end 囧,相比Scala,Ruby的解决方法显得即冗长且丑陋。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-09-16
隐式转换也存在问题,它降低了代码的直观性。后面那个例子尤其如此——运算符重载所具有的缺点,隐式转换也同样有。
|
|
返回顶楼 | |
发表时间:2008-09-16
但这些缺点动态语言不同样存在么?
|
|
返回顶楼 | |
发表时间:2008-09-17
看看C#的,超级简单
public static class Fun{ public static string Reduce(this string str){ var res = (from c in str.ToCharArray() where Char.IsUpper(c) select c).ToArray<char>(); return new string(res); } } 这样就可以attach到任意一个String上(只要你引用它的namespace). |
|
返回顶楼 | |
发表时间:2008-09-17
ray_linn 写道 看看C#的,超级简单
public class StringFun{ public static Reduce(this string str){ //bala bala } } public class Demo{ public static void Main(String[] strs){ String str="Smaple String"; str.Reduce();} } 这样就可以attach到任意一个String上(只要你引用它的namespace). 这个就别拿来说事了,活脱脱模仿javascript原型继承,调用原型的方法 |
|
返回顶楼 | |
发表时间:2008-09-17
回楼上:
C#却是静态的,你检查个类型给我看看?你再怎么着,你还得显式声明,C#却是自动的。 |
|
返回顶楼 | |
发表时间:2008-09-17
请移步:
http://www.cnblogs.com/allenlooplee/archive/2008/06/01/1211520.html PS: 吸纳别人优秀的东西是件非常好的事情,但起码也得谦虚点。 |
|
返回顶楼 | |
发表时间:2008-09-17
请教一个问题,对于需求2,如果还需要增加使得它能与时间类型比较,在Scala中应该如何写?是像这样?
implicit def lessThanOverload(i: Int) = new { def <(str: String) = str.length < i def <(date: Date) = date.... } |
|
返回顶楼 | |
发表时间:2008-09-17
假设就和Date的Year比较吧,这样就可以了:
implicit def lessThanOverload(i: Int) = new { import java.util.Date def <(str: String) = str.length < i def <(date: Date) = date.getYear < i } |
|
返回顶楼 | |
发表时间:2008-09-17
对于隐式转换,我这儿讲的只是它的两个比较简单的应用。
这里有几篇比较不错的文章: scala学习笔记(5) -- implicit type Scala Implicits: a dose of Magic 还有,这里还有个帖子:付出太多,得到太少 - 闲谈函数返回值 我在后面给出了个Scala的解决方法能够解决LZ提出的部分要求,但不知是没人看到还是我的解法不符合要求,没有人对此关心。 |
|
返回顶楼 | |