本文来自fair-jm.iteye.com 转截请注明出处
前端时间买了本 FP in scala(电子版 可以paypal付 双币信用卡就可以) 粗粗地看 看到了Stream惰性求值那章就想自己写一写
按照这本书写了写
于是想了想scala类库中的scala.collection.immutable.Stream中的 #::操作是如何实现的呢:
1 #:: {println(2);2} #:: {println("empty");scala.collection.immutable.Stream.empty[Int]}
#::是惰性求值的 不会对后面的结果求值 所以结果是
res0: scala.collection.immutable.Stream[Int] = Stream(1, ?)
并没有输出 2 和 empty
对于scala的中缀表达式 我们知道要实现中缀 那么这个中缀运算符一定是前面或者后面参数的一个方法 因为这个操作符是以 : 结尾的所以他就是Stream的一个方法 我按照这个思路自己先尝试了下:
package cp5 sealed abstract class Stream[+A] { def take(n: Int): Stream[A] def drop(n: Int): Stream[A] def map[B >: A](f: A => B): Stream[B] def foreach[A](f: A => Unit): Unit = this match { case Empty => case c: Cons[A] => f(c.head) c.tail.foreach(f) } def #::[B >: A](e:B):Stream[B] = Stream.cons(e, this) } case object Empty extends Stream[Nothing] { override def take(n: Int): Stream[Nothing] = Empty override def drop(n: Int): Stream[Nothing] = Empty override def map[B](f: Nothing => B) = Empty } case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A] { lazy val head = h() lazy val tail = t() override def take(n: Int): Stream[A] = { if (n == 1) Cons(h, () => Empty) else Cons(h, () => tail.take(n - 1)) } override def drop(n: Int): Stream[A] = { if (n == 1) tail else tail.drop(n - 1) } override def map[B >: A](f: A => B): Stream[B] = { Stream.cons(f(head), tail.map(f)) } } object Stream { def cons[A, B >: A](h: => B, t: => Stream[A]): Stream[B] = { Cons(() => h, () => t) } def apply[A](e: A*): Stream[A] = { if (e.isEmpty) { Empty } else { Stream.cons(e.head, apply(e.tail: _*)) } } } object Main { def main(args: Array[String]): Unit = { val s = Stream(1, 2, 3, 4, 5, 6).map((i: Int) => i * 2) 1 #:: {println(2);2} #:: {println(4);Stream(3)} } }
没有报错
但遗憾的是在运行的时候会打印出
2
3
没有达到后面参数的惰性求值
后来考虑了一下发现这样做是不对的...如果是Stream的方法的话就一定会对{println(3);Stream(3)}进行求值 得到Stream(3)(不然怎么调用他的方法)
将这个 #:: 写在Stream里肯定是不行的
但这样如何实现呢.... 考虑了一会儿想到不如直接看源码
果不其然 源码的实现 #::并不是Stream的方法:
object Stream extends SeqFactory[Stream] { ... ... /** A wrapper class that adds `#::` for cons and `#:::` for concat as operations * to streams. */ class ConsWrapper[A](tl: => Stream[A]) { def #::(hd: A): Stream[A] = cons(hd, tl) def #:::(prefix: Stream[A]): Stream[A] = prefix append tl } ... ... }
接下来的问题是 我们写的是Stream 他是怎么变为ConsWrapper的呢...
答案就很明显了 用隐式转换..
implicit def consWrapper[A](stream: => Stream[A]): ConsWrapper[A] = new ConsWrapper[A](stream)
仿照写了下 如下:
package cp5 sealed abstract class Stream[+A] { ... } case object Empty extends Stream[Nothing] {...} case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A] { lazy val head = h() lazy val tail = t() override def take(n: Int): Stream[A] = { if (n == 1) Cons(h, () => Empty) else Cons(h, () => tail.take(n - 1)) } ... ... } object Stream { def cons[A, B >: A](h: => B, t: => Stream[A]): Stream[B] = { Cons(() => h, () => t) } def apply[A](e: A*): Stream[A] = { if (e.isEmpty) { Empty } else { Stream.cons(e.head, apply(e.tail: _*)) } } class ConsWrapper[A](tl: => Stream[A]) { def #::(hd: A): Stream[A] = cons(hd, tl) } implicit def convert[A](s: =>Stream[A]):ConsWrapper[A] = { new ConsWrapper(s) } } object Main { def main(args: Array[String]): Unit = { 1 #:: {println(2);2} #:: {println(3);Stream(3)} } }
接下去就是运行 没有输出2 3 运行正常
此外 可以在源码里发现还有个 #::类:
/** An extractor that allows to pattern match streams with `#::`. */ object #:: { def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] = if (xs.isEmpty) None else Some((xs.head, xs.tail)) }
关于这个在洪江大大的博客里有提及:
这里可见scala支持call-by-name 惰性求值 以及 隐式转换 可以实现很多用java根本无法实现的功能 但其实现的方式可能会有点曲折
哎 觉得scala真的挺有趣的 但现在的工作用不上它 只能作为业余爱好略有可惜
相关推荐
基于最新的ffmpeg-3.0实现的dxva2解码,测试4k视频(4096*2304)平均8毫秒解码一帧(不包括存储拷贝),下载源码后建立vs工程,把ffmpeg配置好就可以直接跑起来了。
大多数程序员所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的TCP服务应用; (2)数据报式套接字(SOCK...所以几乎所有的应用都可以用这两类套接字实现。
提供两个宏, stream! 和try_stream! ,允许调用方定义元素的异步流。 这些是使用async & await表示法实现的。 此板条箱可在没有不稳定特征的情况下工作。 stream! 宏返回实现特性的匿名类型。 与Item相关的类型...
deepstream-test1-app_rtsp-master基于Deepstream实现RTSP视频流的读取,c++源代码
本文实例讲述了python实现简单的TCP代理服务器的方法,分享给大家供大家参考。 具体实现代码如下: # -*- coding: utf-8 -*- ''' filename:rtcp.py @desc: 利用python的socket端口转发,用于远程维护 如果连接不到...
这是的#[async] for Futures 0.3循环的重新实现,并且是的实验性实现, 。 #![feature(proc_macro_hygiene, stmt_expr_attributes)] use futures :: stream :: Stream; use futures_async_stream :: for_await; ...
Stream.js 是 Lazy Object Streaming Pipeline 的 JavaScript 实现,灵感来自于 Java 8 Streams API示例代码:Stream(people) .filter({age: 23}) .flatMap("children") .map("firstName") .distinct() ....
Django EventStream EventStream为您的Django应用程序提供API终结点,可以将数据推送到连接的客户端。 数据使用服务器发送事件协议(SSE)发送,其中数据通过永无休止的HTTP响应流式传输。 例如,您可以创建一个...
4.8 FileStream示例2:*实现文件本地分段上传 5.1 简单介绍一下MemoryStream 5.2 MemoryStream和FileStream的区别 5.3 通过部分源码深入了解下MemoryStream 5.4 分析MemorySteam最常见的OutOfMemory异常 5.5 ...
go-stream在golang中提供Java Stream API类似于流操作 用法 package main import ( "github.com/aagu/go-stream" ) func main () { ints := [] int { 1 , 2 , 3 , 4 , 5 , 6 , 7 } stream . New ( ints ). Filter...
npm install stream-union 例子 var cmp = require ( 'typewise-cmp' ) function max ( a , b ) { return 0 <= cmp ( a , b ) ? a : b } function getKey ( item ) { return item . key } function maxValue ( ...
FFMPEG实现RTSP中H264数据流解码 并且实时播放 具体解释参考https://blog.csdn.net/yunge812/article/details/79709307
parallel_stream:Elixir的并行流实现
基于Vue+SpringBoot实现的基于朴素贝叶斯的敏感词判断和视频智能推荐前后端源码+数据库.zip 基于Vue+SpringBoot实现的基于朴素贝叶斯的敏感词...采用KafkaStream和SparkStream以及Flume完成对日志的采集、过滤、处理
python-stream 说明 数据流式框架, 可用作数据清洗, 数据预处理, 数据迁移等应用场景 更优雅的流式数据处理方式 安装 pip install git+https://github.com/sandabuliu/python-stream.git or git clone ...
STREAM- 1.0版1.0版的STREAM(基于SaTellite的径流评估和映射)模型的Matlab实现。 在Test_data和Results中,您可以找到用于测试代码和相应结果的数据集。引文参考 卡米奇(Camici,S.),朱利亚尼(Giuliani),G。...
=泛型实现的惰性Stream类型,其中T : Equatable 。 Stream既是延迟填充的,也是延迟评估的,这使它们便于拖延您不想执行的任务,例如在连续的阶段中执行昂贵的计算。 您可以使用SequenceType构造Stream ,将它们...
spark及stream任务实现框架及使用实例,结果存入mysql数据库,包含了一套最简单的实现框架,方便添加各种简单的任务
(需要ffmpeg) 用法: $ npm install node-rtsp-stream在服务器上: Stream = require('node-rtsp-stream')stream = new Stream({ name: 'name', streamUrl: 'rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k....
Flask-opencv网络摄像头流服务器这是一个简单的python3脚本,可为微型Flask视频网络服务器提供服务,该服务器可通过opencv控制连接的相机/网络摄像头拍照或观看实时视频流。要求为了执行脚本,您需要安装opencv3-> ...