计算机语言那么多,为什么大数据的Spark和Flink选择Scala?
理由如下:
1. 兼容性(极度重用java,学过java的很容易上手scala)
2. 简洁(实现同样功能,代码是java的一半)
3. 高层级(将java抽象封装得更好)
4. 集大成者(当然,用不好也可能变成四不像)
![2ce36eee694f42e73093ff0cf980ddd0.png](https://i-blog.csdnimg.cn/blog_migrate/9fc58cb46146b0cef3febad01c1c368b.png)
代码乱花渐欲迷人眼,浅草才能没马蹄。咱们先有一个感性的认识
![36bf746fe7d092728da0f0868719a96b.png](https://i-blog.csdnimg.cn/blog_migrate/ff704ee461d62cc8accb5d08d4557acc.jpeg)
第一步:一些简单的小例子
Shell解释器:
![d09a5cbc7005a26b0bcf0a0c1da02707.png](https://i-blog.csdnimg.cn/blog_migrate/d75d4101ed0b51939408091508491e41.png)
输入1+2:
![be2dd267724dc860cca4710837066c9b.png](https://i-blog.csdnimg.cn/blog_migrate/f3e13f3b1e34bf3032840a6afde5f9a7.png)
res0,表示结果0,一个冒号(:),跟着表达式的类型(Int),一个等号(=),结果(3)
继续
![af9018780fe65f4fe31485d01667685f.png](https://i-blog.csdnimg.cn/blog_migrate/b3cf453f4e58bf5bf4d94f375c6f14ff.png)
Hello world 万岁
![7214201bec2c115dae42786ce729c986.png](https://i-blog.csdnimg.cn/blog_migrate/26dafc0066f6a12e2548ab15be5eee79.png)
定义一些变量
![046cff15a24fa38c7d3302f9b4139119.png](https://i-blog.csdnimg.cn/blog_migrate/2f8292c9113f7962278b2fc7e4da1f16.jpeg)
定义一些函数
![a1c6e6f10ebe108f2350b63a1b7f190f.png](https://i-blog.csdnimg.cn/blog_migrate/ba1d16c80dea823bfc729a07c60e3ecb.jpeg)
编写几个脚本: Hello.scala
![189cbaa3999703e93e7819b0c56d3041.png](https://i-blog.csdnimg.cn/blog_migrate/2a720e8cc8675bf4b1b3d4494db9b35c.png)
运行:
![a1179a9351e3180633b0d2c73f09bce9.png](https://i-blog.csdnimg.cn/blog_migrate/c9f55b2ede7582e5499e11347696ace3.png)
结果:
![01af8c1a73d42b58f5042e671de45bf9.png](https://i-blog.csdnimg.cn/blog_migrate/75807ed7ee157ab1b9d96cfdc8ad47f1.png)
修改脚本
![d59d5d9094a6c8541cc18949c90362ab.png](https://i-blog.csdnimg.cn/blog_migrate/aff6b133019e1a01cef37216bf218178.png)
运行:
![180976b63f4f00b6efd1eff35825ffd0.png](https://i-blog.csdnimg.cn/blog_migrate/ebee0429ad43832ceb613feffd7a0056.png)
![7e330f575fbfbaa935ad5750976dbd3b.png](https://i-blog.csdnimg.cn/blog_migrate/4f5f221497db1b33bb9c6631e16b560d.png)
讲讲while:
![d9a59f0feca76ecd2eb8e119b6b7c367.png](https://i-blog.csdnimg.cn/blog_migrate/8eda93f8f91ddf381a1da1a23380a9d9.jpeg)
讲讲foreach和for:
![ab23320eb4eaccec5a3e31c9f1d20651.png](https://i-blog.csdnimg.cn/blog_migrate/e8dc8d618de1e2908e891af1ceb6e7de.png)
讲讲数组和方法调用
![ed59ef41b35a4258e9e625fa1a364b83.png](https://i-blog.csdnimg.cn/blog_migrate/53b9d0adda1789011e9ec159892e595e.png)
本例中的to实际上是带一个Int参数的方法。代码0 to 2被转换成方法调用(0).to(2)。 请注意这个语法仅在你显示指定方法调用的接受者时才起作用。不可以写println 10,但是可以写成“Console println 10”。
![7fb12e079b95f68d6e562ba065600aaa.png](https://i-blog.csdnimg.cn/blog_migrate/2cd840115b8870a4dee52997290f48bf.png)
方法调用(续): 当你在一个或多个值或变量外使用括号时,Scala会把它转换成对名为apply的方法调用。于是greetStrings(i)转换成greetStrings.apply(i)。 当然前提是这个类型实际定义过apply方法。所以这不是一个特例,而是一个通则。 类似的例子:带有括号里参数和等号右边的对象的update方法的调用。
![05d619d260e2759597ea7f42e3ea1cb5.png](https://i-blog.csdnimg.cn/blog_migrate/9522e57c21522524f9bda7b6793e887d.png)
讲讲List:
![ed1db7911bd0cf6c45f37cb58647bc65.png](https://i-blog.csdnimg.cn/blog_migrate/8c4b90f68b5e3693b4183f598e6a4c64.jpeg)
如果一个方法被用作操作符标注,如a * b,那么方法被左操作数调用,就像a.*(b)——除非方法名以冒号结尾。这种情况下,方法被右操作数调用。因此,1 :: twoThree里,::方法被twoThree调用,传入1,像这样:twoThree.::(1)。
![dfb72966e140a29236e0ef7938ea13f1.png](https://i-blog.csdnimg.cn/blog_migrate/b02cf9ac556fb554b76b7bea0f48094b.jpeg)
讲讲Tuple元组:
![3d10db7d1b011d8b65978fbc944034c2.png](https://i-blog.csdnimg.cn/blog_migrate/c9d857dd4e948f7834826bc6aafe52c1.png)
第一个元素是以99为值的Int,第二个是"luftballons"为值的String。Scala推断元组类型为Tuple2[Int, String],并把它赋给变量pair。
![897fe95169649a8a16d492154348a884.png](https://i-blog.csdnimg.cn/blog_migrate/024c4bbc1646e2ab5d12fce6c68b49c2.jpeg)
讲讲Set和Map:
![30cf39a7f570bf4ed40484e97534b8d4.png](https://i-blog.csdnimg.cn/blog_migrate/d70dfe74b2353280166d79c838f004ac.jpeg)
![a5fa8d2228189a4aa6b1d95ba789c0f9.png](https://i-blog.csdnimg.cn/blog_migrate/c178f319f67534c38d3c2c255b26f7e1.png)
错误示范
![111d67012bb17b0d1ac8fe2da3f09008.png](https://i-blog.csdnimg.cn/blog_migrate/2bce4550753121ae37308ce0ef45e518.png)
正确示范
![a751625f4dd9254856fdade008c62f83.png](https://i-blog.csdnimg.cn/blog_migrate/8ffb59916b98ec95bcd0c931faac3893.png)
显式定义HashSet
![bc0731de27f569aea650a88d221bf88f.png](https://i-blog.csdnimg.cn/blog_migrate/18f0074348b0114bfe8b9cdac88bd9ad.png)
其他类型的可变、不可变Set,如HashSet等,请自由发挥!
错误示范
![47696d70d37b33c3cc6caf5f2be84e3b.png](https://i-blog.csdnimg.cn/blog_migrate/d2401b1ececd531304e095e69be21531.png)
正确示范(可变映射)
![28be704e00a43b6f99e8d487c12f8e88.png](https://i-blog.csdnimg.cn/blog_migrate/833475bfbc8570c8381a1208a1116eda.png)
讲讲Set和Map: 错误示范 正确示范(可变映射) ->方法可以调用Scala程序里的任何对象,并返回一个包含键和值的二元元组 所以可推断出,scala的map中的键值对是以元组的形式存放的 正确示范(可变映射)
![b11f62f03a4cc0771fad8e33f04b5c29.png](https://i-blog.csdnimg.cn/blog_migrate/c0d24f90970a1632c440965b17154993.png)
讲讲函数式风格:
类java编程(指令式编程)
![2289737f79bfe3e0f93502dd0fc8d7f7.png](https://i-blog.csdnimg.cn/blog_migrate/c7813d4d0581958fc20d645c3b37fbba.png)
加入函数式风格
![24ca32dde488441b3a0901754fba96d5.png](https://i-blog.csdnimg.cn/blog_migrate/d78c95e7dc63536e5e3c293fdcee5982.png)
更函数式
![4d7d89e6abb987c8cce52ed9b4fe9a11.png](https://i-blog.csdnimg.cn/blog_migrate/3b630242ea08300ef74059cce10f53bb.png)
函数的副作用:如果某个函数不返回任何有用的值,就是说其结果类型为Unit,那么那个函数唯一能让世界有点儿变化的办法就是通过某种副作用。
从文件里读取信息:
引入Source:
![8ee6d994e9c87c86c46ef86b74365f32.png](https://i-blog.csdnimg.cn/blog_migrate/f35235befbb5e3995bbee18af7ffee0a.png)
调用自身:
![ec2471cc4170b1b6c198066a2bdb6136.png](https://i-blog.csdnimg.cn/blog_migrate/58d536c9aabbcba4046aa3996349b811.png)
过程解释:
1. 从包http://scala.io引用名为Source的类。
2. 检查是否命令行里定义了至少一个参数。
3. 若是,则第一个参数被解释为要打开和处理的文件名。
4. 表达式Source.fromFile(args(0)),尝试打开指定的文件并返回一个Source对象,在其上调用getLines。函数返回Iterator[String],在每个枚举里提供一行包括行结束符的信息。
5. for表达式枚举这些行并打印每行的长度,空格和这行记录。
6. 如果命令行里没有提供参数,最后的else子句将在标准错误流中打印一条信息。
从文件里读取信息:
![8ee6d994e9c87c86c46ef86b74365f32.png](https://i-blog.csdnimg.cn/blog_migrate/f35235befbb5e3995bbee18af7ffee0a.png)
![8ee6d994e9c87c86c46ef86b74365f32.png](https://i-blog.csdnimg.cn/blog_migrate/f35235befbb5e3995bbee18af7ffee0a.png)
复习一下函数式风格:
Source.fromFile(args(0)).getLines.foreach(line => print(line.length + " " + line))
![34974b362f59988b79288e0e31350da0.png](https://i-blog.csdnimg.cn/blog_migrate/f6256b9542717fbdd05f270738d5ac04.png)
第二步:类、字段、方法(对比java)
类:
![adabc0bd2cbb1df5a77a319801f1e017.png](https://i-blog.csdnimg.cn/blog_migrate/0d645726bc14c6ec939a91b56c5bed02.png)
在Scala里把成员公开的方法是不显式地指定任何访问修饰符。换句话说,你在Java里要写上“public”的地方,在Scala里只要什么都不要写就成。Public是Scala的缺省访问级别。
![dcc406f982e5068cb3f46e34d903aa56.png](https://i-blog.csdnimg.cn/blog_migrate/cfd567ae66ae64fed0d45544ce769005.png)
类续(引入方法):
![6e720cc15cc07ea3ae1e33515e8d6460.png](https://i-blog.csdnimg.cn/blog_migrate/443aea7984ccd5215eafc3fff0c1fb21.png)
当你去掉方法体前面的等号时,它的结果类型将注定是Unit。
![2108e07341b1109c81404e815ad7ace2.png](https://i-blog.csdnimg.cn/blog_migrate/9efc5a7316661b8a586d4e0541260c92.png)
带有大括号但没有等号的,在本质上当作是显式定义结果类型为Unit的方法。
![f41168a0a70b09690798600303b9d0c5.png](https://i-blog.csdnimg.cn/blog_migrate/23af2dbb4977b0e16762c2d655cfdfee.png)
用“=”返回一个非Unit的值
单例对象:
Scala比Java更面向对象的一个方面是Scala没有静态成员。替代品是,Scala有单例对象:singleton object。除了用object关键字替换了class关键字以外,单例对象的定义看上去就像是类定义。
![61f0b842c1b770938044dc43e4f7bd8f.png](https://i-blog.csdnimg.cn/blog_migrate/3c4d14ba31c50ccc5aafc2955a0dc4b0.png)
当你在应用程序中需要一个新的唯一账号时,调用Account.newUniqueNumber()即可。
单例对象的分类:
1.独立对象
不与伴生类共享名称的单例对象称为独立对象。它可以用在很多地方,例如作为相关功能方法的工具类,或者定义Scala应用的入口点。跟java的静态方法类似。
2. 伴生对象 当单例对象与某个类共享同一个名称时,它就被称为是这个类的伴生对象(companion object)。类和它的伴生对象必须定义在同一个源文件中。类被称为是这个单例对象的伴生类(companion class)。类和它的伴生对象可以互相访问其私有成员。
![bf491c06bf1127e52c8a0db36f9c2b5c.png](https://i-blog.csdnimg.cn/blog_migrate/7bf8b622d4f244358052e4e26b6af04f.png)
继承自抽象类的例子:
扩展类的一个有用的使用场景是给出可被共享的缺省对象。举例来说,考虑在程序中引入一个可撤销动作的类:
![4d4b932189a8c390cae80078923b783e.png](https://i-blog.csdnimg.cn/blog_migrate/6e5209b913ed3309f3c4cfbad5331b32.png)
运行scala程序:
在Java中,一个类要能独立运行,那么必须具有静态的main方法。 Scala借鉴了这种模式。在Scala中,为了运行一个Scala程序,你必须定义一个Scala对象并为其定义一个main方法:
![8b587754c60cd69411d76603bd26766a.png](https://i-blog.csdnimg.cn/blog_migrate/5471855d24a01d115731894bc0d5d8ff.png)
为了使代码更简洁,Scala还提供了另外一种运行Scala程序的方式,那就是直接继承scala.Application接口(Trait)。
![8840645da2cdacadf80a203ca69a0fe0.png](https://i-blog.csdnimg.cn/blog_migrate/886762231519c07c35bc743268935f0e.png)
原理: 之所以这里无须定义main方法,那是因为在Application这个接口中定义了一个main方法,main方法在执行时会初始化RunAppWithoutMain这个对象,并执行它的主构造方法,而所 有直接写在对象中的代码都会被scala编译器收集到主构造方法中,于是就被运行了。 直接继承自Application导致的副作用:
1. 无法接受命令行参数。因为args参数不会被传入
2. 在Scala中,如果一个程序是多线程的,那么这个程序必须具有一个main方法。所以第二种写法只能适用于单线程的程序
3. Application这个接口在执行一个程序的代码之前,需要进行一些初始化。而某些JVM不会对这些初始化代码进行优化。
一些基本类型:
Scala的基本类型与Java的对应类型范围完全一样。这让Scala编译器能直接把Scala的值类型:value type实例,如Int或Double,在它产生的字节码里转译成Java原始类型。
![717d699471b1eb0fcbca9ed430178786.png](https://i-blog.csdnimg.cn/blog_migrate/2773858cc2c4add38a8b179d7fea9fab.jpeg)
富包装器:
基本类型可以通过隐式转换:implicit conversion,使用富包装器的方法。 每个基本类型,都有一个“富包装器”可以提供许多额外的方法。
![d5f8fd82a1ed7f7ef805bc2d0608e214.png](https://i-blog.csdnimg.cn/blog_migrate/5a7effeb507b0471aa3a742415200344.jpeg)
案例类(Case Class):
case class User(name: String, role: String = "user", addTime: Instant = Instant.now())
特点1:不可变
![802d22af6e6a6a80f6b80d6e51f94d85.png](https://i-blog.csdnimg.cn/blog_migrate/649fa71936365661f9084909e445e7e9.png)
当我们修改 u1.role 时,u2 就会受到影响,Java 的解决方式是要么基于 u1.role 深度克隆一个新对象出来,要么新创建一个 Role 对象赋值给 u2。
特点2:对象拷贝
![20bfb38f47d3d5aad90716b72285eadf.png](https://i-blog.csdnimg.cn/blog_migrate/72f2f851a5091661b6438cdb933805b1.png)
特点3:调试信息清晰
![4eaa28b51bd0a024ca626950302da4fd.png](https://i-blog.csdnimg.cn/blog_migrate/6dc666452061363f6159bac3abc1a84d.png)
![c89d458b7b83785d27db0c23b7a03e62.png](https://i-blog.csdnimg.cn/blog_migrate/8b1f02a93011c0fd34f4b8ffa0518974.jpeg)
![e7e30ea0086471d5a394836f07945b6b.png](https://i-blog.csdnimg.cn/blog_migrate/20b74098d6bd3c97df550383cd90cedb.png)
![2f5915fbc3ad9eb33e1781584d306023.png](https://i-blog.csdnimg.cn/blog_migrate/deeaf5c87028a68036da0590e2208053.png)
最后一步:控制结构和特质
if:
![cddc466b40da2eda507ef0fe60a62dd9.png](https://i-blog.csdnimg.cn/blog_migrate/5f8f2404b4d3008e00a24073c065c97c.png)
while:
![78b2f52beeb40c202196aa43567f1885.png](https://i-blog.csdnimg.cn/blog_migrate/9c2b3a5eb00149f12a8dabd662adbf76.png)
for:
![0f3f16783c37ff95a9282b4f25a21592.png](https://i-blog.csdnimg.cn/blog_migrate/46de9ca027d5530fdd6bacc4ab3fc779.png)
for-yield:
![ac69d794cb3fbda04e621745280db4c1.png](https://i-blog.csdnimg.cn/blog_migrate/90d12f282c51bf4f959d515762528c88.png)
首先把包含了所有当前目录的文件的名为filesHere的Array[File],转换成一个仅包含.scala文件的数组。对于每一个对象,产生一个Iterator[String](fileLines方法的结果,定义展示在代码7.8中),提供方法next和hasNext让你枚举集合的每个元素。这个原始的枚举器又被转换为另一个Iterator[String]仅包含含有子字串"for"的修剪过的行。最终,对每一行产生整数长度。这个for表达式的结果就是一个包含了这些长度的Array[Int]数组。
请注意放置yield关键字的地方。对于for-yield表达式的语法是这样的: for {子句} yield {循环体}
try-catch:
![6c847df8185004e3c715c7f7b09f3329.png](https://i-blog.csdnimg.cn/blog_migrate/72d5714f24cfe2865a314896259e70b4.png)
也有finally:
![1e788ed36e81c4de74c2b7b21ff1077d.png](https://i-blog.csdnimg.cn/blog_migrate/ad9577df3c1b3f8ccbd0cf30f8df1f92.png)
match(模式匹配):
![7eb924a69d1df75c954fd0ffbb2b1432.png](https://i-blog.csdnimg.cn/blog_migrate/9a2edb3a2731d232bd9a8a82d9c5ca16.jpeg)
特质trait:
特质:是Scala里代码复用的基础单元。特质封装了方法和字段的定义,并可以通过混入到类中重用它们。 不像类的继承那样,每个类都只能继承唯一的超类,类可以混入任意个特质。
![5ed366a80ddea3f47fcce7f59e39914a.png](https://i-blog.csdnimg.cn/blog_migrate/70136d308500a790f2af079934d955b7.png)
这个特质名为Philosophical。由于没有声明超类,因此和类一样,有个缺省的超类AnyRef。
一旦特质被定义了,就可以使用extends或with关键字,把它混入到类中。
既可以带抽象方法,也可以带具体方法
![29f4321f859c8f9df351e915e1bf6d4c.png](https://i-blog.csdnimg.cn/blog_migrate/d63d2a7f510c9fd17cbd133bcef7b124.png)
特质可以将对象原本没有的方法与字段加入对象中 如果特质和对象改写了同一超类的方法, 则排在右边的先被执行.
![c74d7527b3379c11ebc202476ac4a760.png](https://i-blog.csdnimg.cn/blog_migrate/da9912e9bd084ee72e24658bca81d073.png)
特质的构造顺序
1. 调用超类的构造器;
2. 特质构造器在超类构造器之后、类构造器之前执行;
3. 特质由左到右被构造;
4. 每个特质当中,父特质先被构造;
5. 如果多个特质共有一个父特质,父特质不会被重复构造
6. 所有特质被构造完毕,子类被构造。
特质trait——字段
具体字段
![6652ef76bcdcf81bd6970d1f2a7ab757.png](https://i-blog.csdnimg.cn/blog_migrate/3cb37d87279b6842e4d169f2742b2f54.png)
1. 混入Ability特质的类自动获得一个run字段.
2. 通常对于特质中每一个具体字段, 使用该特质的类都会获得一个字段与之对应.
3. 这些字段不是被继承的, 他们只是简单的加到了子类中.任何通过这种方式被混入的字段都会自动成为该类自己的字段, 这是个细微的区别, 却很重要 。
抽象字段
![828efc18fb6142b0af7bd3553e270064.png](https://i-blog.csdnimg.cn/blog_migrate/3bc4ef837395ecdc3702e5d954ae6e3c.png)
特质中未被初始化的字段在具体的子类中必须被重写 。
最后:特质不能有构造器参数. 每个特质都有一个无参构造器. 值得一提的是, 缺少构造器参数是特质与类唯一不相同的技术差别. 除此之外, 特质可以具有类的所有特性, 比如具体的和抽象的字段, 以及超类.。
![4ec9034985e36e0108bb28297a467ee5.png](https://i-blog.csdnimg.cn/blog_migrate/a6b1ab28e57d682a1c3423dade750173.png)
隐式转换-mongodb库对接
利用隐式转换,我们可以在不改动三方库代码的情况下,将我们的数据类型与其进行无缝对接。例如我们通过实现一个隐式转换,将 Scala 的 JsObject 类型无缝地对接到了 MongoDB 的官方 Java 驱动的查询接口中,看起就像是 MongoDB 官方驱动真的提供了这个接口一样。 同时我们也可以将来自三方库的数据类型无缝集成到现有的接口中,也只需要实现一个隐式转换方法即可。
![24f554c5ea13d704809c22681666c64d.png](https://i-blog.csdnimg.cn/blog_migrate/2c7c41476a0eb2c58cbaf946614f3ad3.png)
值比较
Java的比较:
![0e457f0dcc2ec39d4531f3461eed3a7a.png](https://i-blog.csdnimg.cn/blog_migrate/911be14adec1400e8b1444b3ec8c1cf7.png)
Scala值比较:
![4f56cb50f519ba748a36dbd8179e74e9.png](https://i-blog.csdnimg.cn/blog_migrate/143e5420c1a06a683e6a02f64993276a.png)
Scala引用比较:
![4d0cf96b8e0ca176a47e45b42c71b3a3.png](https://i-blog.csdnimg.cn/blog_migrate/96b07a6b12eb7cbfbb52b3cd5094940c.png)
类型推断
错误代码:
![123b42d424c4913efb23300f93310b04.png](https://i-blog.csdnimg.cn/blog_migrate/5660cef55ded0d48ed245c0d1130d6bf.png)
Java正确代码:
![82f610568156446d07b4fefd07f537df.png](https://i-blog.csdnimg.cn/blog_migrate/0fa23a59ea440356249cbf2dfa90da37.png)
Scala正确代码:
![6ca3b1141d8fc204f89e519cbf409b51.png](https://i-blog.csdnimg.cn/blog_migrate/4d148fe5fd621c586b8fa09de786b73c.png)
Actor Model
1. 概念理解
Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
Actor的特征:
Ø ActorModel是消息传递模型,基本特征就是消息传递
Ø 消息发送是异步的,非阻塞的
Ø 消息一旦发送成功,不能修改
Ø Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的
什么是Akka
Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。
spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。
2. 例:Actor简单例子发送接收消息
import scala.actors.Actor
class myActor extends Actor{
def act(){
while(true){
receive {
case x:String => println("save String ="+ x)
case x:Int => println("save Int")
case _ => println("save default")
}
}
}
}
object Lesson_Actor {
def main(args: Array[String]): Unit = {
//创建actor的消息接收和传递
val actor =new myActor()
//启动
actor.start()
//发送消息写法
actor ! "i love you !"
}
}
3. 例:Actor与Actor之间通信
case class Message(actor:Actor,msg:Any)
class Actor1 extends Actor{
def act(){
while(true){
receive{
case msg :Message => {
println("i sava msg! = "+ msg.msg)
msg.actor!"i love you too !"
}
case msg :String => println(msg)
case _ => println("default msg!")
}
}
}
}
class Actor2(actor :Actor) extends Actor{
actor ! Message(this,"i love you !")
def act(){
while(true){
receive{
case msg :String => {
if(msg.equals("i love you too !")){
println(msg)
actor! "could we have a date !"
}
}
case _ => println("default msg!")
}
}
}
}
object Lesson_Actor2 {
def main(args: Array[String]): Unit = {
val actor1 = new Actor1()
actor1.start()
val actor2 = new Actor2(actor1)
actor2.start()
}
}
WordCount
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
object WordCount {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setMaster("local").setAppName("WC")
val sc = new SparkContext(conf)
val lines :RDD[String] = sc.textFile("./words.txt")
val word :RDD[String] = lines.flatMap{lines => {
lines.split(" ")
}}
val pairs : RDD[(String,Int)] = word.map{ x => (x,1) }
val result = pairs.reduceByKey{(a,b)=> {a+b}}
result.sortBy(_._2,false).foreach(println)
//简化写法
lines.flatMap { _.split(" ")}.map { (_,1)}.reduceByKey(_+_).foreach(println)
}
}
部分代码补充:
样例类
case class Person1(name:String,age:Int)
object Lesson_CaseClass {
def main(args: Array[String]): Unit = {
val p1 = new Person1("zhangsan",10)
val p2 = Person1("lisi",20)
val p3 = Person1("wangwu",30)
val list = List(p1,p2,p3)
list.foreach { x => {
x match {
case Person1("zhangsan",10) => println("zhangsan")
case Person1("lisi",20) => println("lisi")
case _ => println("no match")
}
} }
}
}
模式匹配
object Lesson_Match {
def main(args: Array[String]): Unit = {
val tuple = Tuple6(1,2,3f,4,"abc",55d)
val tupleIterator = tuple.productIterator
while(tupleIterator.hasNext){
matchTest(tupleIterator.next())
}
}
/**
* 注意点:
* 1.模式匹配不仅可以匹配值,还可以匹配类型
* 2.模式匹配中,如果匹配到对应的类型或值,就不再继续往下匹配
* 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
*/
def matchTest(x:Any) ={
x match {
case x:Int=> println("type is Int")
case 1 => println("result is 1")
case 2 => println("result is 2")
case 3=> println("result is 3")
case 4 => println("result is 4")
case x:String => println("type is String")
// case x :Double => println("type is Double")
case _ => println("no match")
}
}
}
trait 特性
trait Read {
val readType = "Read"
val gender = "m"
def read(name:String){
println(name+" is reading")
}
}
trait Listen {
val listenType = "Listen"
val gender = "m"
def listen(name:String){
println(name + " is listenning")
}
}
class Person() extends Read with Listen{
override val gender = "f"
}
object test {
def main(args: Array[String]): Unit = {
val person = new Person()
person.read("zhangsan")
person.listen("lisi")
println(person.listenType)
println(person.readType)
println(person.gender)
}
}
object Lesson_Trait2 {
def main(args: Array[String]): Unit = {
val p1 = new Point(1,2)
val p2 = new Point(1,3)
println(p1.isEqule(p2))
println(p1.isNotEqule(p2))
}
}
trait Equle{
def isEqule(x:Any) :Boolean
def isNotEqule(x : Any) = {
!isEqule(x)
}
}
class Point(x:Int, y:Int) extends Equle {
val xx = x
val yy = y
def isEqule(p:Any) = {
p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
}
}
学习指南
RUNOOB菜鸟教程 Scala 教程 https://www.runoob.com/scala/scala-tutorial.html
Scala 开发教程_w3cschool https://www.w3cschool.cn/scaladevelopmentguide/
官方教程 https://docs.scala-lang.org/zh-cn/tour/tour-of-scala.html
PlayScala社区https://scalacn.cool/