Scala 重难点总结

news/2025/1/11 21:05:29/

目录

  • 一. 难点总结
    • 1. 数据类型
    • 2. 函数与方法的区别
    • 3. object、class、case class、case object、package object
    • 4. 伴生对象和 apply() 到底有什么用
    • 5. 模式匹配 unapply(),case class 和 偏函数
    • 6. 隐式转换
    • 7. 泛型
  • 二.参考文章

一. 难点总结

1. 数据类型

在这里插入图片描述

scala">def test1():Any = {List}// 类似于 Java 的 Object
def test2():AnyRef = {List}def test3():AnyVal = {1}

Unit、Null、Nothing、Nil、None 的区别:

scala">// AnyVal 类型的子类
def test4():Unit = {}// AnyRef 类型的子类
def test5():Null= {null}// Nothing 表示抛出异常 或者 集合为空,是最底层的子类
def test6():Int = {if(1 < 0) 1 else throw new Exception }  // 实际会返回 Nothingdef test7():List[Nothing] = {List()}def test8():List[Nothing] = {Nil}// None 是对象 不是类,它的类型是 Option[Nothing]
def test9():Option[String] = { Map("France"->"Paris").get("a") }  //返回 Some(Paris) 或者 None 对象

2. 函数与方法的区别

首先了解下函数与方法的区别:Scala 方法是类的一部分,而 函数 是一个对象可以赋值给一个变量。方法本质上是一个特殊的函数。

scala> val a = 1                           //数据类型赋值给变量
a: Int = 1scala> val f1 = (x:Int,y:Int) => x + y     //函数赋值给变量
f1: (Int, Int) => Int = <function>         //<function>就是 x + y 这个函数体,是一个 lambda 表达式scala> def m(x: Int) = x + 3              //定义方法
m: (x: Int)Intscala> val f2 = m _                       //方法转换为函数
f2: Int => Int = <function2>

Scala 中的函数则是一个完整的对象。方法中可以传函数,对象构造器也可以传函数。map 函数也称为高阶函数。

scala">def map[U: ClassTag](f: T => U): RDD[U] = withScope {  //方法的形参为一个函数val cleanF = sc.clean(f)new MapPartitionsRDD[U, T](this, (_, _, iter) => iter.map(cleanF)) //主构造器
}
scala">class Test{def m(x: Int) = x + 3                    //方法val f = (x: Int) => x + 3                //变量val f2 = (x: Int, y: Int) => x + y       //变量def m1(f:(Int,Int) => Int) : Int = {     //方法的形参为一个函数f(2,6)}print(m1(f2))   // 输出 8
}

3. object、class、case class、case object、package object

  1. object:相当于单例对象,可以直接使用。
  2. class:类定义
  3. case class:
    • 是用于创建不可变(immutable)且具有模式匹配能力的类。
    • 重写了 toString、equals、hashCode 方法。
    • 伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象。
    • 提供 unapply 方法使模式匹配可以工作。
  4. case object:既是一个单例对象,又具有模式匹配的能力。
  5. package object:包下的单例对象,对象名与包名相同。

4. 伴生对象和 apply() 到底有什么用

伴生对象 => 单例对象,当做工具类使用,尽量来操作这个对象。
延申知识点:java 中有 static 和 单例。

scala">val a = Array(1,2,3)  
// 使用的是 Array 的这个伴生对象,伴生对象() => 就是调用对象中的 apply() 方法。

apply() => 语法糖,val a = Array(1,2,3) 底层 new 的细节被屏蔽了。

scala">object ApplyApp {def main(args: Array[String]): Unit = {for(i<- 1 to 10){ApplyTest.incr}println(ApplyTest.count)  //结果为10,说明object本身就是一个单例对象val b=ApplyTest()    //因为在object的apply已经new了,所以此处就不用了new了//此时调用Object ApplyTest里面的apply方法val c=new ApplyTest()println(c)              //此处c默认使用toString方法c()                     //此处调用class 里面的apply方法/* 即类名()=->object里面的apply方法:val b=ApplyTest()*   对象()==>class里面的apply方法:val c=new ApplyTest()*/}
}
scala">//class ApplyTest是object ApplyTest的伴生类
class ApplyTest{def apply() ={println("class ApplyTest里面的apply方法被调用")}
}//object ApplyTest是class ApplyTest的伴生对象
object ApplyTest{println("伴生对象进入")var count=0def incr={count=count+1}
//一般情况下,我们在object里面的apply方法中去new classdef apply() ={println("object ApplyTest里面的apply方法被调用")new ApplyTest}println("伴生对象离开")
}

5. 模式匹配 unapply(),case class 和 偏函数

unapply 是接受一个对象,从对象中提取出相应的值,主要用于模式匹配中。

scala">class Money(val value: Double, val country: String) {}
object Money {def apply(value: Double, country: String) : Money = new Money(value, country)def unapply(money: Money): Option[(Double, String)] = {if(money == null) {None} else {Some(money.value, money.country)}}
}val money = Money(10.1, "RMB")
money match {case Money(num, "RMB") =>  println("RMB: " + num)case _ => println("Not RMB!")
}

直接使用 case class,不用自己实现 unapply 方法

scala">val person = new Person("Alice", 25)person match {case Person("Alice", 25) => println("Hi Alice!")case Person("Bob", 32) => println("Hi Bob!")case Person(name, age) =>println("Age: " + age + " year, name: " + name + "?")}// 样例类
case class Person(name: String, age: Int)

偏函数:就是用花括号包围一些 case 语句。

scala">object PartialFunctionExample extends App {val multiplyByTwo: PartialFunction[Int, Int] = {case x => x * 2}println(multiplyByTwo(2)) // 输出: 4
}

6. 隐式转换

主要作用一:模拟新的语法

  • select中的 $ 是隐式转换
import spark.implicits._
df.select($"name", $"age" + 1).show()implicit class StringToColumn(val sc: StringContext) {def $(args: Any*): ColumnName = {new ColumnName(sc.s(args: _*))}
}
  • map中的 -> 是隐式转换
val map = Map(1 -> "one")implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {@inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)def →[B](y: B): Tuple2[A, B] = ->(y)
}

主要作用二:类型增强与扩展

  • rdd 的 api 并没有 toDF() 方法,如果要使用必须的隐式转化
import spark.implicits._val peopleRDD: RDD[String] = spark.sparkContext.textFile("D:\\study\\people.txt")
val peopleDF: DataFrame = peopleRDD.map(_.split(",")) //RDD.map(x => People(x(0), x(1).trim.toInt)) //RDD.toDF()implicit def rddToDatasetHolder[T : Encoder](rdd: RDD[T]): DatasetHolder[T] = {DatasetHolder(_sqlContext.createDataset(rdd))
}

Spark 中的 RDD 以及它的子类是没有 groupByKey, reduceByKey 以及 join 这一类基于 key-value 元组的操作的,但是在你使用 RDD 时,这些操作是实实在在存在的,Spark 正是通过隐式转换将一个 RDD 转换成了 PairRDDFunctions

implicit def rddToPairRDDFunctions[K, V](rdd: RDD[(K, V)])(implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null): PairRDDFunctions[K, V] = {new PairRDDFunctions(rdd)
}

7. 泛型

类泛型

  1. java泛型
public class People<T>{//成员变量private T t;
}
  1. scala 主构造器泛型
scala">class People[T](val t: T)
  1. 视图界定
scala">class MaxValue[T <: Comparable[T]](val first:T, val second:T){ //泛型def bigger = if(first.compareTo(second) > 0) first else second
}print(new MaxValue[Integer](1, 2).bigger)   

Integer 实现了 Comparable[Integer] 接口,能正常运行。

  1. 泛型和隐式转换
scala">class MaxValue[T <: Comparable[T]](val first:T, val second:T){ //泛型def bigger = if(first.compareTo(second) > 0) first else second
}print(new MaxValue[Int](1, 2).bigger)   

Int 没实现了 Comparable[Int] 接口,不能能正常运行。
将 T <: Comparable[T] 改为 T <% Comparable[T],会隐式转换将 Int 转为 Integer,就能正常运行。

二.参考文章

Scala 方法与函数
Scala中的下划线使用总结
为什么Scala在类中没有静态成员?
java中的静态类
秒懂设计模式之建造者模式
scala中的apply方法与unapply方法
【Scala】使用Option、Some、None,避免使用null
scala 里怎样判空,比如java中防止空指针异常而做出的Null判断,以及字符串blank判断等?
Scala之隐式转换
SparkSql学习之:toDF方法的由来(源码)


http://www.ppmy.cn/news/1443472.html

相关文章

代码+视频,R语言绘制生存分析模型的时间依赖(相关)性roc曲线和时间依赖(相关)性cindex曲线

ROC曲线分析是用于评估一个因素预测能力的手段&#xff0c;是可以用于连续型变量分组的方法。在生存分析中&#xff0c;疾病状态和因素取值均会随时间发生变化。而标准的ROC曲线分析将个体的疾病状态和因素取值视作固定值&#xff0c;未将时间因素考虑在分析之中。在这种情况下…

C语言趣味代码(四)

这一篇主要编写几个打字练习的小程序&#xff0c;然后通过这些小程序的实现来回顾复习我们之前学过的知识&#xff0c;然后通过这写打字练习的小程序来提升我们的打字技术和编程技术。 1. 打字练习 1.1 基本打字练习 1.1.1 基本实现 首先我们来制作一个用于计算并显示输入一…

玄子Share-Shell编程之条件语句

玄子Share-Shell编程之条件语句 条件测试操作 test命令 测试表达式是否成立&#xff0c;若成立返回0&#xff0c;否则返回其他数值 格式1&#xff1a;test 条件表达式 格式2&#xff1a;[ 条件表达式 ] # 至少应有一个空格文件测试 [ 操作符 文件或目录 ][rootlocal…

Java的static

在Java中&#xff0c;static是一个关键字&#xff0c;用于声明属性、方法、代码块或内部类。static的主要特性是它关联于类而不是类的实例&#xff08;对象&#xff09;。因此&#xff0c;你可以在不创建对象的情况下直接通过类名访问静态成员。 下面我将详细解释static的各种用…

335GB,台北地区倾斜摄影OSGB数据V0.2版介绍!

前几天发布了台北地区倾斜摄影OSGB数据第一个版本(139GB,台北倾斜摄影OSGB数据V0.1版),虽然数据还是一个半成品&#xff0c;完全没想到热度很高&#xff0c;很多读者对这份数据都有比较浓厚的兴趣&#xff0c;在这里首先感谢各位读者的大力支持与鼓励&#xff0c;给了我持续更新…

使用JavaScript日历小部件和DHTMLX Gantt的应用场景(一)

DHTMLX Suite UI 组件库允许您更快地构建跨平台、跨浏览器 Web 和移动应用程序。它包括一组丰富的即用式 HTML5 组件&#xff0c;这些组件可以轻松组合到单个应用程序界面中。 DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足项目管理应用…

Mysql(数据库)知识详解终章~{日志,Mycat}

数据库里面的日志是记录数据库运行期间状态信息的文件&#xff0c;Mycat是一个开源的分布式数据库系统。 数据库日志主要包括错误日志、查询日志、慢查询日志、事务日志和二进制日志等几大类。具体如下&#xff1a; 错误日志&#xff1a;记录了数据库服务器启动、运行或停止时…

代谢组数据分析六:其他分析

Other Analysis {#OtherAnalysis} 除了常见的功能分析,还有其他的功能分析方法或R包。本章节主要介绍其他功能分析的方法以及结果解析。 所需要的数据:链接: https://pan.baidu.com/s/1xezhpZRebCsct0AtlDpSHg 提取码: 2djy FELLA: an R package to enrich metabolomics d…