用Scala实现Stream(一个惰性的链表)数据结构

深入了解Linux内核--页面回收和页交换 这种做法背后的原因是这样:如果内核仅限于不活动页,较大型的分配通常无法满足,对繁忙的内核来说,较大的连续物理内存区间中包含活动页的可能性是非常高的。每次调用 shrink_zone 时,将扫描的活动和不活动页的数目,即 nr_scan_active 和 nr_scan_inactive ,需要分别加上内存域中当前活动和不活动页的数目右移 priority 位(再加1),所加的数值约等于内存域中当前活动/不活动页数整除以2 priority 的商。接下来将删除页向量的内容,以便为缓存中的新页腾出空间。 阅读详情

这个例子来源于scala圣经级教程《Functional Programming in Scala》,由于本人跟着书中的代码敲了一遍,然后写了点测试代码验证了一下正确性,所以就放在这做个备忘吧。贴出来只是为了方便自己,如果看不懂,但是又感兴趣的就去看原书吧……

package laziness

trait Stream[+A] {

  import laziness.Stream._

  def toListRecursive: List[A] = this match {
    case Cons(h, t) => h() :: t().toListRecursive
    case _ => List()
  }

  def toList: List[A] = {
    @annotation.tailrec
    def go(s: Stream[A], acc: List[A]): List[A] = s match {
      case Cons(h, t) => go(t(), h() :: acc)
      case _ => acc
    }

    go(this, List()).reverse
  }

  def toListFast: List[A] = {
    val buf = new scala.collection.mutable.ListBuffer[A]

    def go(s: Stream[A]): List[A] = s match {
      case Cons(h, t) => buf += h(); go(t())
      case _ => buf.toList
    }

    go(this)
  }

  def take(n: Int): Stream[A] = {
    this match {
      case Cons(h, t) if n > 1 => cons(h(), t().take(n - 1))
      case Cons(h, _) if n == 1 => cons(h(), empty)
      case _ => empty
    }
  }

  @annotation.tailrec
  final def drop(n: Int): Stream[A] = this match {
    case Cons(h, t) if n > 0 => t().drop(n - 1)
    case _ => this
  }

  def takeWhile(f: A => Boolean): Stream[A] = this match {
    case Cons(h, t) if (f(h())) => cons(h(), t() takeWhile f)
    case _ => empty
  }

  /**
    * 有栈溢出风险
    */
  def foldRight[B](z: => B)(f: (A, => B) => B): B =
    this match {
      case Cons(h, t) => f(h(), t().foldRight(z)(f))
      case _ => z
    }


  def foldLeft[B](z: => B)(f: (=> B, A) => B): B =
    this match {
      case Empty => z
      case Cons(h, t) => t().foldLeft(f(z, h()))(f)
    }

  def exists(p: A => Boolean): Boolean = foldRight(false)((a, b) => p(a) || b)

  def forAll(f: A => Boolean): Boolean = foldRight(true)((a, b) => f(a) && b)

  def takeWhile_1(f: A => Boolean): Stream[A] = foldRight(empty[A])((h, t) => if (f(h)) cons(h, t) else empty)

  def headOption: Option[A] = foldRight(None: Option[A])((h, _) => Some(h))

  def map[B](f: A => B): Stream[B] = foldRight(empty[B])((h, t) => cons(f(h), t))

  def filter(f: A => Boolean): Stream[A] = foldRight(empty[A])((h, t) => if (f(h)) cons(h, t) else t)

  def append[B >: A](s: => Stream[B]): Stream[B] = foldRight(s)((h, t) => cons(h, t))

  def flatMap[B](f: A => Stream[B]): Stream[B] = foldRight(empty[B])((h, t) => f(h).append(t))

  def mapViaUnfold[B](f: A => B): Stream[B] = unfold(this) {
    case Cons(h, t) => Some(f(h()), t())
    case _ => None
  }

  def takeViaUnfold(n: Int): Stream[A] = unfold((this, n)) {
    case (Cons(h, t), 1) => Some((h(), (empty, 0)))
    case (Cons(h, t), n) if n > 1 => Some((h(), (t(), n - 1)))
    case _ => None
  }

  def takeWhileViaUnfold(f: A => Boolean): Stream[A] = unfold(this) {
    case Cons(h, t) if f(h()) => Some(h(), t())
    case _ => None
  }

  def zipWith[B, C](s2: Stream[B])(f: (A, B) => C): Stream[C] =
    unfold((this, s2)) {
      case (Cons(h1, t1), Cons(h2, t2)) => Some((f(h1(), h2()), (t1(), t2())))
      case _ => None
    }

  def zip[B](s2: Stream[B]): Stream[(A, B)] = zipWith(s2)((_, _))

  def zipAll[B](s2: Stream[B]): Stream[(Option[A], Option[B])] = zipWithAll(s2)((_ -> _))

  def zipWithAll[B, C](s2: Stream[B])(f: (Option[A], Option[B]) => C): Stream[C] =
    Stream.unfold((this, s2)) {
      case (Empty, Empty) => None
      case (Cons(h, t), Empty) => Some(f(Some(h()), Option.empty[B]) -> (t(), empty[B]))
      case (Empty, Cons(h, t)) => Some(f(Option.empty[A], Some(h())) -> (empty[A], t()))
      case (Cons(h1, t1), Cons(h2, t2)) => Some(f(Some(h1()), Some(h2())) -> (t1(), t2()))
    }

  def startWith[A](s: Stream[A]): Boolean = zipAll(s).takeWhile(!_._2.isEmpty) forAll {
    case (h, h2) => h == h2
  }

  def tails: Stream[Stream[A]] = unfold(this) {
    case Empty => None
    case s => Some((s, s drop 1))
  } append Stream(empty)

  def hasSubSequence[A](s: Stream[A]): Boolean = tails exists (_ startWith s)

  def scanRight[B](z: B)(f: (A, => B) => B): Stream[B] = foldRight((z, Stream(z)))((a, p0) => {
    lazy val p1 = p0
    val b2 = f(a, p1._1)
    (b2, cons(b2, p1._2))
  })._2

  @annotation.tailrec
  final def find(f: A => Boolean): Option[A] = this match {
    case Empty => None
    case Cons(h, t) => if (f(h())) Some(h()) else t().find(f)
  }

}

case object Empty extends Stream[Nothing]

case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

object Stream {

  def cons[A](hd: => A, t1: => Stream[A]): Stream[A] = {
    lazy val head = hd
    lazy val tail = t1
    Cons(() => head, () => tail)
  }

  def empty[A]: Stream[A] = Empty

  def apply[A](as: A*): Stream[A] = if (as.isEmpty) Empty else cons(as.head, apply(as.tail: _*))

  val ones: Stream[Int] = cons(1, ones)

  def constant[A](a: A): Stream[A] = {
    lazy val tail: Stream[A] = Cons(() => a, () => tail)
    tail
  }

  def from(n: Int): Stream[Int] = cons(n, from(n + 1))

  val fibs = {
    def go(f0: Int, f1: Int): Stream[Int] = cons(f0, go(f1, f0 + f1))

    go(0, 1)
  }

  def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z) match {
    case Some((h, s)) => cons(h, unfold(s)(f))
    case None => empty
  }

  def unfoldViaFold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z).fold(empty[A])((p: (A, S)) => cons(p._1, unfold(p._2)(f)))

  def unfoldViaMap[A, S](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z).map((p: (A, S)) => cons(p._1, unfold(p._2)(f))).getOrElse(empty[A])

  val fibsViaUnfold = unfold((0, 1)) {
    case (f0, f1) => Some((f0, (f1, f0 + f1)))
  }

  def fromViaUnfold(n: Int) = unfold(n)(n => Some(n -> (n + 1)))

  def constantViaUnfold[A](a: A) = unfold(a)(_ => Some(a -> a))

  def onesViaUnfold = unfold(1)(_ => Some(1 -> 1))


  def main(args: Array[String]): Unit = {

    println(Stream.ones.asInstanceOf[Cons[Int]].h())
    println(Stream.ones.asInstanceOf[Cons[Int]].h)
    println(Stream.ones.asInstanceOf[Cons[Int]].t().asInstanceOf[Cons[Int]].h())


    val f = (to: Int, from: Int) => if(from < to) Some(from , from + 1) else None
    val  rangeToN = (from: Int, to: Int) => unfold(from)(f.curried(to))
    val rangeNum = rangeToN(0, 10).toList
    println(rangeNum)

    println(Stream.ones.take(10))
    println(Stream.ones.take(10).toList)
    println(Stream.fibsViaUnfold.take(10).toList)
    println(Stream.fibs.take(10).toList)

    println(Stream(1, 3, 5, 7, 9))
    println(Stream(1, 3, 5, 7, 9).toList)


    println(Stream.ones.zipWith(Stream.fibs)(_ -> _).take(10))
    println(Stream.ones.zipWith(Stream.fibs)(_ -> _).take(10).toList)


    println(Stream.ones.exists( (a: Int) => a == 1))

    println(Stream.from(0).exists( (a: Int) => a == 11))

    println(Stream.from(0).takeWhile( (a: Int) => a < 10))

    println(Stream.from(0).takeWhile( (a: Int) => a < 10).toList)

    println(Stream.ones.map(_ * 5).take(6).toList)


//    println(Stream.ones.foldRight(0)(_ + _)) //栈溢出

//    Stream.ones.exists( (a: Int) => a == 0) //栈溢出

//    Stream.ones.foldLeft(0)(_ +  _) //栈溢出

    println(Stream.ones.take(33).foldLeft(0)(_ +  _))

    println(Stream.ones.take(33).toListFast)
    println(Stream.ones.take(33).drop(29).toListFast)


    println(Stream.from(1).take(8).headOption.get)


    println(Stream.ones.take(2).append(Stream.constant(4).take(2)).toListFast)

    println(Stream.ones.take(2).append(Stream.constant(4).take(2)).startWith(Stream.ones.take(2)))
    println(Stream.ones.take(2).append(Stream.constant(4).take(2)).startWith(Stream.ones.take(3)))


    println(Stream.from(1).take(5).tails.toListRecursive.map(_ toList))


    println(Stream.from(1).take(5).toListFast)

    println(Stream.from(1).take(5).scanRight(0)(_ + _).toListFast)


    println(Stream.from(1).take(5).find(_ == 3).getOrElse(-1))
    println(Stream.from(1).take(5).find(_ == 9).getOrElse(-1))

    println(Stream.empty.toList)

    println(Stream.empty[Any].map[String](_.toString))

  }

}


上述代码的运行结果是:

1
laziness.Stream$$$Lambda$3/1108411398@62043840
1
List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
Cons(laziness.Stream$$$Lambda$3/1108411398@35fb3008,laziness.Stream$$$Lambda$4/584634336@7225790e)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
Cons(laziness.Stream$$$Lambda$3/1108411398@531be3c5,laziness.Stream$$$Lambda$4/584634336@52af6cff)
List(1, 3, 5, 7, 9)
Cons(laziness.Stream$$$Lambda$3/1108411398@12843fce,laziness.Stream$$$Lambda$4/584634336@3dd3bcd)
List((1,0), (1,1), (1,1), (1,2), (1,3), (1,5), (1,8), (1,13), (1,21), (1,34))
true
true
Cons(laziness.Stream$$$Lambda$3/1108411398@3c09711b,laziness.Stream$$$Lambda$4/584634336@5cc7c2a6)
List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
List(5, 5, 5, 5, 5, 5)
33
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
List(1, 1, 1, 1)
1
List(1, 1, 4, 4)
true
false
List(List(1, 2, 3, 4, 5), List(2, 3, 4, 5), List(3, 4, 5), List(4, 5), List(5), List())
List(1, 2, 3, 4, 5)
List(15, 14, 12, 9, 5, 0)
3
-1
List()
Empty
从零到一:基于RK3399的VME控制器Linux驱动开发全流程(PCIE+FPGA篇) 本文详细介绍了基于RK3399和FPGA的VME控制器Linux驱动开发全流程,涵盖PCIE设备驱动开发、FPGA接口设计及系统集成调试。通过实战指南,开发者可掌握从硬件配置到软件实现的完整技术栈,特别适合工业控制系统开发。重点解析了RK3399与FPGA协同工作的关键技术要点。 阅读详情

相关推荐

Flink toAppendStream与toRetractStream的区别

前言 通常我们在需要输出Table表数据时需要转换成DataStream流进行输出,然后转换流有两种模式toAppendStream追加模式、toRetractStream更新模式 toAppendStream:追加模式 接收端口数据,测试追加模式 代码示例 import org.apache.flink.streaming.api.scala._ import org.apache.flink.table.api.{EnvironmentSettings, Table} import org.ap

菜鸟也学大数据的博客 5669

103、scala-链表之单向双向

一、什么是链表 链表是有序的列表,但是它在内存中是存储如下: 总结: 链表是一个有序列表 链表的数据,在内存空间不一定是连续分布的 链表又分单向、双向或者循环 区别: 1、单向链表 2、双向链表 3、循环链表(单向循环,双向循环) 如下图 使用场景及优缺点: 单向链表: 1、单向链表需要实现队列,建设头结点是尾部,入队速度快,但是每次出队需要遍历到最后一个节点 2、实现栈则比较完美 3、链表移除数据需要临时节点来记录待删除节点的前一个节点 双向链表: 1、头尾节点都有并且是双向,则实现队列不用遍

风子的博客 439

为什么Java8中的StreamAPI不如Scala快?

1997年,Sun公司发布了Java1.0版本,这个版本在语法上和功能实现上都非常先进。到目前为止,已有两版Java1.x版本已经出现,并且随着时间的推移,Java的功能也在不断完善和更新。而1.8版本带来的Stream API,就是Java编程的一个重要里程碑。2014年,Oracle宣布将Java8正式命名为Java SE 8。很多开发者纷纷表示,由于java8提供的Stream API功能强大、方便,代码更加优雅易读,所以java8正在改变软件开发的方向,使编程更加高效、简洁。

AI天才研究院 1400

Scala中Stream的应用场景及其实现原理

假设一个场景 需要在50个随机数中找到前两个可以被3整除的数字。 听起来很简单,我们可以这样来写: 1 2 3 4 5 6 7 8 9 def randomList = (1 to 50).map(_ => Random.nextInt(100)).toList def isDivisibleBy3(n: Int) = { val isDivisible = n % 3 == 0 println(s"$n $isDivisible") isDiv

dingyufei的博客 638

flink toAppendStream 报错 红线

这个导入改成下划线: 不显示toAppendStream 方法; import org.apache.flink.table.api.bridge.scala._

yy的博客 745

flink实战--flinkSQL 回撤流原理解析与案例讲解

简介 使用flinkSQL处理实时数据当我们把表转化成流的时候,需要使用toAppendStream与toRetractStream这两个方法。稍不注意可能直接选择了toAppendStream。这个两个方法还是有很大区别的,下面具体介绍。 toAppendStream与toRetractStream的区别 追加模式:只有在动态Table仅通过INSERT更改修改时才能使用...

阿华田的博客 1万+

手机拍照也能玩高光谱?教你用TensorFlow Lite在Android上实现实时RGB转高光谱

本文介绍了如何利用TensorFlow Lite在Android设备上实现实时RGB到高光谱的图像重构技术。通过深度学习模型优化和移动端部署策略,使智能手机具备专业级光谱分析能力,适用于农业检测、化妆品分析等多个领域。

weixin_29091105的博客 247

scala里的List/Stream/View机制浅析

List机制浅析scala里的List就是单向链表,一般通过下面方式来组装一个List:val l = 1 :: 2 :: 3 :: NilNil是空List,::是右结合操作符,所以上述写法相当于: Nil.::(3).::(2).::(1) 我们来看看::连接符是如何实现的:sealed abstract class List[+A] ..... { ... def isEmpty:

tlxamulet的博客 1835

FAST-LIO2实战:从零搭建香港大学火星实验室SLAM框架(附官方数据集测试指南)

本文提供了一份详细的FAST-LIO2实战指南,帮助读者从零开始搭建香港大学火星实验室开源的这一高效激光惯性里程计框架。内容涵盖系统环境配置、依赖安装、源码编译、官方数据集测试以及参数调优,旨在让开发者快速上手并应用于机器人SLAM项目。

ppp33的博客 689

别再死记硬背GNN公式了!用PyTorch Geometric从零实现一个GraphSAGE(附完整代码)

本文通过PyTorch Geometric从零实现GraphSAGE模型,深入解析图神经网络的核心原理与实战应用。文章提供完整代码示例,涵盖环境配置、邻居采样、信息聚合等关键步骤,帮助开发者掌握图表示学习技术,避免陷入公式推导的困境。适合希望将GNN应用于实际项目的中级开发者和学生。

weixin_42530570的博客 348

scala写算法-List、Stream、以及剑指Offer里部分题目基于scala解法

Stream(immutable) Stream是惰性列表。实现细节涉及到lazy懒惰求值、传名参数等等技术(具体细节详见维基百科-求值策略)。 Stream和List是scala中严格求值和非严格求值两个代表性不可变函数式数据结构。 考虑字符串拼接的表达式"foo"+"bar"的到"foobar",空串""就是这个操作的单位元(identity,数学中又称幺元),也就是说s+""或者""+s的值...

weixin_30483013的博客 288

对计算机专业来说学历真的重要吗?

我本科学校是渣渣二本,研究生学校是985,现在毕业五年,校招笔试、面试,社招面试参加了两年了,就我个人的经历来说下这个问题。 这篇文章很长,但绝对是精华,相信我,读完以后,你会知道学历不好的解决方案,记得帮我点赞哦。 先说结论,无论赞不赞同,它本质就是这样:对于技术类工作而言,学历五年以内非常重要,但有办法弥补。五年以后,不重要。 目录: 张雪峰讲述的事实 我看到的事实 为什么会这样 ...

启舰 55万+

Scala Immutable Collection(集合)

1.scala.collection.immutable层次结构如下: List使用 scala> val a = List(1,2,3,4) a: List[Int] = List(1, 2, 3, 4)scala> val b = 0 :: a // 0连接a b: List[Int] = List(0, 1, 2, 3, 4)scala> val c = "x" :: "y" :: "z"

竹杖芒鞋轻胜马~ 3332

Midscene.js(2):代码集成 + 桥接模式(Bridge Mode)的使用「喂饭教程」

本文将手把手教你从零开始搭建一个 Node.js 项目,集成 Midscene.js,并利用其桥接模式实现对 Chrome 浏览器的自动化操作。我们将通过具体的实例,来展示 Midscene.js 的便捷性与 AI 能力的结合。

blues_C的博客 1847

YOLOv11损失函数原理与源码解读:从调参血泪史到源码级优化

本文深入解析YOLOv11目标检测模型的损失函数设计,揭示其相比前代的关键改进。重点剖析了回归损失中动态权重的小目标优化、分类损失的带温度系数softmax、以及目标损失的自适应阈值机制等创新点。作者通过源码分析指出常见实现陷阱,如梯度回传的正确处理方式、标签分配的匹配策略等。结合实战经验,给出针对小目标检测、类别误判等典型问题的调参建议,并分享实用的调试工具代码片段。最后强调损失函数调参需结合具体任务,指出后处理对实际部署效果的重要影响。全文以工程实践为导向,为开发者提供可直接落地的优化思路。

as1225120794的博客 442

《Scala CookBook》Chapter11

《Scala CookBook》Chapter11 List 2.1scala的List类是不可变的,大小及其中元素都不能修改。由链表实现,包含常用的head,tail,isEmpty方法。大多数在List上的操作都会涉及递归算法,将列表且分为头部和尾部。 现在有一个需求:如果一个链表的顺序是5,4,3,2,1。那么怎么才能不改变链表的情况下逆序打印出1,2,3,4,5. 答:可以使用递归...

说文科技,做有态度的研究。 585

OpenClaw实战系列03:Slack/Telegram国际版接入实战指南

在当今的软件开发和工作流自动化中,将项目管理工具与即时通讯平台集成已成为提高团队协作效率的关键。OpenClaw作为一个开源的自动化工具,通过接入Slack和Telegram国际版,可以实现实时通知、自动化任务触发和团队协作的无缝对接。本文将详细介绍如何实现OpenClaw与这两个主流即时通讯平台的集成。OpenClaw是一个开源的自动化工作流引擎,支持多种触发器和执行器,能够帮助开发团队实现CI/CD流程、任务调度、监控告警等自动化场景。模块化设计:支持插件化扩展多触发器支持。

PeterPan的博客 590

vavr:让你像写Scala一样写Java

Hystrix是Netflix开源的限流、熔断降级组件,去年发现Hystrix已经不再更新了,而在github主页上将我引导到了另一个替代项目——resilience4j,这个项目是基于Java 8开发的,并且只使用了vavr库,也就是我们今天要介绍的主角。Lambda表达式既然要谈vavr,那么先要谈为什么要使用vavr,vavr是为了增强Java的函数式编程体验的,那么这里先介绍下Java中的...

十指波课堂的博客 164

15、远程操作水下航行器(ROV)的非线性控制系统设计

本文探讨了远程操作水下航行器(ROV)的非线性控制系统设计,重点介绍了多变量PID控制、改进的PD控制和滑模控制三种方法。详细阐述了各控制策略的原理、建模与仿真过程,并通过对比分析其在稳态误差、振荡、抖振及跟踪效果等方面的性能表现。文章还提出了针对不同控制方法的优化建议,并给出了选择合适控制策略的决策流程,为ROV高精度运动控制提供了系统性解决方案。

sun99的博客 158

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

数组数据结构:从基础概念到高级应用全解析

数组作为计算机科学中最基础的数据结构,其核心特点是内存连续存储和O(1)随机访问。这种线性表结构通过索引直接访问元素的特性,使其在算法优化和系统性能调优中具有独特优势。从底层原理看,数组的连续内存布局充分利用了CPU缓存行预取机制,在图像处理、科学计算等场景中展现出极高的性能。现代编程语言如Java的ArrayList和Python的List基于动态数组实现,通过扩容策略平衡空间与时间效率。在算法领域,数组衍生出滑动窗口、双指针等经典技巧,并支撑着快速排序等高效算法。理解数组的内存模型和访问特性,是优化程序

weixin_30376083的博客 370

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

树与森林遍历全解析:从递归迭代到工程实践

在数据结构与算法领域,树形结构是组织层次化数据的核心模型,广泛应用于文件系统、DOM树、组织架构等场景。其访问原理基于系统性的遍历算法,主要包括深度优先(前序、中序、后序)和广度优先(层序)两种策略。从技术价值看,遍历不仅是数据访问的基础,更是实现序列化、依赖分析、规则提取等高级功能的骨架。在工程实践中,递归实现简洁但需警惕栈溢出风险,迭代法则通过显式管理栈或队列提供更稳定的控制。针对多叉树和森林,可通过孩子兄弟表示法转换或循环处理每棵树来适配遍历逻辑。本文结合递归与迭代的对比、栈溢出排查及遍历顺序导致的典

weixin_30621959的博客 337

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

scala的stream流

Scala的流的实现在Stream中。 主要用到的实现类是Cons类。 @SerialVersionUID(-602202424901551803L) final class Cons[+A](hd: A, tl: =&gt; Stream[A]) extends Stream[A] { override def isEmpty = false override def head =...

不说话装高手 3589

Scala中Stream讲解

//使用#::得到一个stream:numsForm(参数:参数类型) : 返回值类型 = 参数 #:: numsForm(m+1) ==>> 两个参数必须一致 def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1) //传递一个值,并打印stream集合 val one = numsForm(0) print...

weixin_42771366的博客 1699
上一篇: 使用Scala实现Either数据结构
下一篇: 用Scala实现一个纯函数风格的引用透明的伪随机数生成器
lhever_
博客等级 码龄14年 213粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值