最通俗易懂的Scala初级知识
- 为什么要学习scala?
- 什么是scala?
- 实战初级scala
唯一的目的就是:能够看懂Spark源码;
学习新的一门编程语言(第二门):是很快的;(类比着学,所有的编程语言都是思路相通的)只不过语法不一样;
- 编程语言:java,php,.net,c++,scala,python
- 因为所有的编程语言只是发送指令,电脑干活;电脑都是由一堆的硬件组成;(电路板);只认二进制数据(0,1);电脑只识别:二进制语言;人类的语言电脑听不懂;(才有了操作系统做为翻译);编程语言相当于各个领域;
- 世界上有各种各样的语言;中国人说汉语,法国人说法语;他们两个人之间是无法沟通的,得需要找一个懂英语的人,翻译(英语是世界通用语言);人类学习母语是很累的,但是再学习第二语言是很快的;不同的语言描述的都是同一个事物,只不过有不同的叫法而已
- 门门通,不如一门精;你学习好一门编程语言(学精);如果将来的系统需要用到其它的编程,你放心,肯定会有这门编程语言的高手也与你对接;(接口)通过网络传输,传输的内容是json;
1.介绍scala
Scala:它不是一门新的编程语言,而是一个结合体;
scala要想运行,必须安装jdk;它的编译和运行在jdk基础之上;(scala就是java的一个框架而已)
它的语法和javascript很像; 一个方法的参数类型居然还可以是方法;(函数编程)(和lambda表达式的思想很
像)
官网:https://www.scala-lang.org/;它都会有一段话来描述一下这个xx是什么东东;
文档:https://docs.scala-lang.org/
2.入门
1)在scala中,类型可是方法;在java中类型(基本数据类型和引用类型;在javascript中类型又多了一个function;scala就是把javascript和java结合起来)。
2)要定义一个变量,或者准备要使用一个类型,必须定义变量是什么类型;(强类型语言);scala是一个弱类型语言(变量不需要指定类型);javascript也是一个弱类型语言。
3)java文件和scala文件都是编译成class文件;在java文件中定义的类,在scala可以使用,反过来也是可以的;
可以直接在浏览器上码scala代码;
打开:https://scalafiddle.io
在左侧窗格中粘贴println(“Hello, world!”)
代码块:直接用大括号括起来,代码块
函数和方法类似,但是两个不相等;
方法是被def修饰,
函数是木有被def修饰
剩下的都一样
3.名词介绍
Java | Scala |
---|---|
Interface | traits |
枚举 | Case class |
4.统一类型
Scala:的类型有哪些,scala写变量的时候不需要写类型(人家自己推断,你可以省略也可以加上)
1.Any是所有类型的超类型,也称为顶级类 型。它定义了一些通用的方法如equals、hashCode和toString。Any有两个直接子类:AnyVal和AnyRef。
2.AnyVal代表值类型。有9个预定义的非空的值类型分别是:Double、Float、Long、Int、Short、Byte、Char、Unit和Boolean。Unit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。
3.AnyRef代表引用类型。所有非值类型都被定义为引用类型。在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object。
4.Nothing和Null
4.1.Nothing是所有类型的子类型,也称为底部类型。没有一个值是Nothing类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。
4.2.Null是所有引用类型的子类型(即AnyRef的任意子类型)。它有一个单例值由关键字null所定义。Null主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。我们将在后面的章节中介绍null的替代方案。
5.类
Scala中的类是用于创建对象的蓝图,其中包含了方法、常量、变量、类型、对象、特质、类,这些统称为成员。类型、对象和特质将在后面的文章中介绍。
6.特质
特质 (Traits) 用于在类 (Class)之间共享程序接口 (Interface)和字段 (Fields)。 它们类似于Java 8的接口。 类和对象 (Objects)可以扩展特质,但是特质不能被实例化,因此特质没有参数。
7.元组
1)Map:是一个集合,集合中的每一个元素都有key和value(共两个);
2)元组也是一个集合,集合中的每一个元素都有22值
3)在 Scala 中,元组是一个可以容纳不同类型元素的类。 元组是不可变的。
4)当我们需要从函数返回多个值时,元组会派上用场。
5)Scala 中的元组包含一系列类:Tuple2,Tuple3等,直到 Tuple22。 因此,当我们创建一个包含 n 个元素(n 位于 2 和 22 之间)的元组时,Scala 基本上就是从上述的一组类中实例化 一个相对应的类,使用组成元素的类型进行参数化。
8. 混编–mixin
/* 这是一个抽象类 */
abstract class A {val message: String
}
/* 这是一个类,实现了抽象类A */
class B extends A {val message = "I'm an instance of class B"
}
/* 这是一个特质,居然还可以继承自一个抽象类 */
trait C extends A {def loudMessage = message.toUpperCase()
}
/* 一个类实现一个接口使用extends; 如果这个类有父类(使用extends);接口要换成with*/
class D extends B with Cval d = new D
println(d.message) // I'm an instance of class B
println(d.loudMessage) // I'M AN INSTANCE OF CLASS B
9.高阶函数
1)高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。在Scala中函数是“一等公民”,所以允许定义高阶函数。这里的术语可能有点让人困惑,我们约定,使用函数值作为参数,或者返回值为函数值的“函数”和“方法”,均称之为“高阶函数”。
2)说白了:就是方法的参数或者返回值,居然还可以是一个函数(高阶函数)
3)既然Scala编译器已经知道了参数的类型(一个单独的Int),你可以只给出函数的右半部分,不过需要使用_代替参数名(在上一个例子中是x)
10.柯里化
方法可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化。
/* scala中是可以方法套用方法* 方法定时的时候有两个参数列表;* * 类似于:方法的重载* */def fun3(a:Int)(c:Int,b:Int) :Unit ={println("---a--" + a);println("---b--" + b);print("---c--" + c);}/* 调用方法 */fun3(2)(3,4);/* 第一步 fun3(2)(3,4)* fun4==fun3(30)* 第二步* fun4(40,50)* 使用一个方法进行了替代(3,4)* _表示省略后面的形参列表;* * 柯里化:* */def fun4 = fun3(30)_;/* 调用方法 */fun4(40,50);
11.隐藏参数
1)隐式(IMPLICIT)参数
如果要指定参数列表中的某些参数为隐式(implicit),应该使用多参数列表。例如:
def execute(arg: Int)(implicit ec: ExecutionContext) = ???
2)方法可以具有 隐式 参数列表,由参数列表开头的 implicit 关键字标记。 如果参数列表中的参数没有像往常一样传递, Scala 将查看它是否可以获得正确类型的隐式值,如果可以,则自动传递。
3)Scala 将查找这些参数的位置分为两类:
Scala 在调用包含有隐式参数块的方法时,将首先查找可以直接访问的隐式定义和隐式参数 (无前缀)。
然后,它在所有伴生对象中查找与隐式候选类型相关的有隐式标记的成员。
4)更加详细的关于 Scala 到哪里查找隐式参数的指南请参考 常见问题
5)在下面的例子中,我们定义了一个方法 sum,它使用 Monoid 类的 add 和 unit 方法计算一个列表中元素的总和。 请注意,隐式值不能是顶级值。
/* 定义了一个抽象类 */
abstract class Monoid[A] {/* 把两个参数相加,得到一个返回值(通过方法名判断出来) */def add(x: A, y: A): A/* 定义一个变量,unit:木有返回值 */def unit: A
}/* object:单例的对象 */
object ImplicitTest {/* 创建了一个string类型的对象 */implicit val stringMonoid: Monoid[String] = new Monoid[String] {/* 对这里面的两个方法做了实现;java.lang.String这个类里面有一个方法叫concat */def add(x: String, y: String): String = x concat ydef unit: String = ""}/* 创建了一个int类型的对象 */implicit val intMonoid: Monoid[Int] = new Monoid[Int] {/* 对这里面的两个方法做了实现 */def add(x: Int, y: Int): Int = x + ydef unit: Int = 0}/* 参数是一个List,我们在定义方法的时候无法知道这个List里面放的是什么类型要想知道List里面放的是什么类型,只有在调用方法的时候才会知道如何知道在调用方法的时候,如果List里面放的是Int,就默认的调用intMonoid如果List里面放的是String,就默认的调用stringMonoid要想实现这一个效果,就得加上implicit;(隐式参数)*/def sum[A](xs: List[A])(implicit m: Monoid[A]): A =if (xs.isEmpty) m.unitelse m.add(xs.head, sum(xs.tail))def main(args: Array[String]): Unit = {/* 这个List里面放的是int */println(sum(List(1, 2, 3))) // uses IntMonoid implicitly/* 这个List里面放的是String */println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly}
}
12.实战scala初级
标准的HelloWorld:
package com.jinghangzz.scala/*** scala的HelloWorld*/
object HelloWorld {/*** def:(修饰符)* main:方法名* 形参:变量:类型* Unit:void,此方法木有返回值*/def main(args: Array[String]): Unit = {/* 两种写法* scala中特有的写法;可以省略掉* System.out.println* 就是在写scala代码的时候,每一行结束的时候分号可写可不写(建议写上)* */println("==南宋四大名将==")/* 是java的写法;* java和scala通用* */System.out.println("==岳飞,韩世忠,刘光世,张俊==");}
}
简化版本的HelloWorld
package com.jinghangzz.scala/*** 是HelloWorld的简化版本* 省掉main方法*/
object HwApp extends App {println("==岳飞,韩世忠,刘光世,张俊==");
}
概览
package com.jinghangzz.scala/*** 基础知识* 变量(主要)和常量* 变量有三个要素:类型,名字值;* 类型有哪些:* 名字:(标识符)* 值:讲类型的时候,已经讲过了每一个类型的取值范围* 在定义方法的时候,如果是def修饰的方法,=后面不能跟上>,* 如果是在定义一个函数funtion,后面得跟上>*/
object Base {def main(args: Array[String]): Unit = {println("==宋太祖:(赵匡胤)==");/** java代码:int i = 0 ; (变量三要素)* */var i = 10 println("i====" + i );var j = 20 ; println("j====" + j );j = 30 ; println("j====" + j );/* 10 + 30 = 40 */println("i + j = " + (i + j )) ; /** 常量:final i = 0 ; * val:常量 不能修改值* */val z = 0 ; /* 最全的写法* var 变量名:类型 = 值* */var a:Int = 10 ; /* 函数:方法;五要素* 修饰符,方法名,形参,方法体;返回值* * 木有名字;匿名函数* *///(a:Int,b:Int) => {a + b} ; /* 函数起了一个名字* 先定义方法,再拿一个变量接收,这个写法和javascript一样* * 在java中,最外层是类,第一层:属性和方法;是否允许有第三层也是方法;(方法绝对不可以套方法)* 而scala允许方法调用方法* */var fun1 = (a:Int,b:Int) => {a + b}/* 上面的写法和下面的写法一样 */def fun2(a:Int,b:Int) :Int = {a + b}/* 调用函数 */var result = fun1(10,30);println("==结果==" + result);/* scala中是可以方法套用方法* 方法定时的时候有两个参数列表;* * 类似于:方法的重载* */def fun3(a:Int)(c:Int,b:Int) :Unit ={println("---a--" + a);println("---b--" + b);print("---c--" + c);}/* 调用方法 */fun3(2)(3,4);/* 第一步 fun3(2)(3,4)* fun4==fun3(30)* 第二步* fun4(40,50)* 使用一个方法进行了替代(3,4)* _表示省略后面的形参列表;* * 柯里化:* */def fun4 = fun3(30)_;/* 调用方法 */fun4(40,50);/* 所有的代码都可以省略 * 如果方法的形参木有,小括号可以省略* 如果方法木有返回值,那么方法名后面跟的是:返回值可以省略* 如果大括号(方法体)只有一行,那大括号可以省略* */def fun5 = println("a + b ===== 测试一下");/* 调用* 如果方法木有形参,小括号可以省略* */fun5;/* ========创建一个对象======== */var p1 = new Person(23,"赵匡胤");println("==toString==" + p1.toString())/* 调用方法 */p1.sayvar p2:Person = new Person(24,"赵匡义");p2.say/* 类比较的是栈的上值 */println("p1 == p2===" + (p1 == p2) )/* 创建案例类 */var po1 = Point(3,4)var po2 = Point(3,4);println("==po1==" + po1.toString())/* 案例类默认已经重写了equals方法,它比较的就是值 */println("po1 == po2===" + (po1 == po2) )/* object调用方法* object使用的时候可以不用new对象* */IdFactory.create ; IdFactory.create ; }
}/* 创建一个新的类* 后面可以直接跟上属性,这叫构造方法* */
class Person(age:Int,name:String)
{/*** 说话的方法* def say() :Unit = {}*/def say = println(this.age + "===say==" + this.name)
}/* * 样例类:(Case Class)* 样例类一般不用于可变的对象,并且可以做值比较(只有四类八种基本数据类型;==)* 样例类可以不用new来创建对象* 样例类:toString:默认就是构造方法,同时把值带上了* Point(点)*/
case class Point(x:Int,y:Int)/**
object;对象的意思 ,
默认就是单例;一个jvm只能有一个java对象
*/
object IdFactory
{var i:Int = 0 ; /*** 方法*/def create = {println("i的值:" + i );/* 自加1 */i = i + 1 ; }
}
特质(接口)
package com.jinghangzz.scala/*** 特质:接口*/
object TraitTest {def main(args: Array[String]): Unit = {println("==赵光义(宋太宗)==赵炅")/* 创建对象 */var p1 = new Per;p1.eatp1.sleep/* 创建一个男人 */var m:Man = new Man();m.eat();m.sleep;}
}/*** 定义一个接口*/
trait IAdmin
{/* 抽象方法 */def eat():Unit ;/* 抽象方法 */def sleep;
}/*** 一个类实现一个接口,要重写接口中所有的方法*/
class Per extends IAdmin {def eat(): Unit = {println("=Per==eat=");}def sleep: Unit = {println("=Per==sleep=");}
}/*** 写一个男人,继承自Per*/
class Man extends Per
{/* 对父类的方法不满意,要重写* 必须加上override* */override def eat() :Unit ={println("==Maneat==");}
}
13.统一类型+类的代码
package com.jinghangzz.scala/*** 基础类型*/
object BaseValue {def main(args: Array[String]): Unit = {println("==aa==");/* 调用方法 *///base_01//base_02base_03}/*** 统一类型*/def base_01 {/* 定义一个List */var list = List(1,"a","b",true,() =>{} );/* * foreach:这个方法有一个参数;这个参数的类型是函数;* java中:方法的参数是接口,而且接口只一个抽象方法;(lambda表达式的前题条件)* foreach:方法的参数是函数;目前做的工作是调用;* 提示:f: Any => U;函数有一个参数,木有返回值* */list.foreach( t => println("==循环=:" + t) );}/*** 类*/def base_02 {/* 定义一个类* 属性后面直接跟值:表示默认值* * 不带val或var的参数是私有的,仅在类中可见。* */class Person(var age:Int = 24,var name:String){/* 私有的属性,是为了提供读写器 */private var _weight:Int = 0 ;/* get方法 */def weight = _weight ; /* set方法* 注意下对于setter方法的特殊语法:这个方法在getter方法的后面加上_=,后面跟着参数* */def weight_= (weight:Int) :Unit ={this._weight = weight }override def toString() :String ={/* 如果有返回值,最后一行代码,可以把return省略 *///"name:" + this.name + ";age:" + this.age ; /* s:占位符:$(占位符)后面直接跟上属性的名字 */s"name:$name;age:$age" }}/* 创建对象 */var p1 = new Person(20,"张三");println("toString:" + p1.toString());/* 创建对象 * 属性=值,单独的赋值,另外的一个,表示使用默认值* */var p2 = new Person(name="李四");println("toString:" + p2.toString());println("==p2.weight==" + p2.weight)/* 设置值 *///p2.weight_=(300);p2.weight = 300 ; println("==p2.weight==" + p2.weight)}/*** 元组*/def base_03 ={/* 创建一个元组 */var tuple2 = ("张三",20):Tuple2[String,Int];println("toString:" + tuple2); /* 取第二个值 */println("key:" + tuple2._1); println("value:" + tuple2._2); /* 就是一个类 */var tuple3 = new Tuple2("李四",20);println("key:" + tuple3._1); println("value:" + tuple3._2); /* 第三种写法 */var tuple4 = ("王五",30);println("key:" + tuple4._1); println("value:" + tuple4._2); /* 解构元组 */var (name,age) = tuple4 ; println("name" + name); println("age:" + age); /* 准备一个List* List里面放的可以是元组;tuple2* */var list = List( ("张三",20),("李四",30), ("王五",40));/** 参数是一个函数;* f: Any => U* f: ((String, Int)) => U* */list.foreach( t => println(t._1 + "==循环==>" + t._2))/* 模式匹配 */ list.foreach( t => {/* 模式匹配特别像switch case* case后面跟的是条件;* */t match {case ("张三",age) => println("张三,你老了,年龄:" + s"$age");case temp if(temp._1 == "李四") => {/* 如果访问的是元组;s后面的占位符要使用${变量名._2} */println(temp._1 + ",你更老了,年龄:" + s"${temp._2}");}case _ => println("===你更老===");}})/* List的另外一种循环* <-右边是集合,左边是临时的变量* * 把方法的名字叫数学符号;+,-,++* */for( (name,age) <- list){println(name + "==循环==>" + age)} /* ==========高阶函数==========* 方法的参数是函数;* 方法的返回值也可以是函数* */var list2 = List(1,35,73,10)/* 第一种写法 */var doubleInt = (t:Int) => {var t2 = t * 2 ;println("第一种写法==循环==" + t2 )};list2.foreach(doubleInt)/* 第二种写法 */list2.foreach( t => {var t2 = t * 2 ;println("第二种写法==循环==" + t2 )} );/* 第三种写法* =>左半已经可以自动推断参数的类型,那就可直接省略掉* _不能和其它类型运算* */list2.foreach( println(_) )/* 柯里化 */var result = list2.foldLeft(0)(_ + _);println("----result----" + result ) }
}
最通俗易懂的Scala初级知识相关推荐
- 23篇大数据系列(二)scala基础知识全集(史上最全,建议收藏)
作者简介: 蓝桥签约作者.大数据&Python领域优质创作者.管理多个大数据技术群,帮助大学生就业和初级程序员解决工作难题. 我的使命与愿景:持续稳定输出,赋能中国技术社区蓬勃发展! 大数据系 ...
- 台式电脑如何截屏_如何选购台式电脑显卡?小白装机通俗易懂的独立显卡知识指南...
对于游戏玩家和3D设计人员以及挖矿人员来说,显卡的选择无疑是重中之重,重要性可能甚至超过了核心硬件-CPU.我们在选购独立显卡的时候,通常小白只看显存大小,其实这是最大的选购误区,然而决定显卡的性能不 ...
- Scala初级实践——统计手机耗费流量(1)
Scala初级实践--统计手机耗费流量(1) [实验描述] 本实验主要使用Scala语言来实现对手机流量的计算.在该实验中,共有四个需求: 1)统计每一个手机号耗费的总上行流量.下行流量.总流量 2) ...
- 04-如何选购台式电脑显卡?小白装机通俗易懂的独立显卡知识指南
对于游戏玩家和3D设计人员以及挖矿人员来说,显卡的选择无疑是重中之重,重要性可能甚至超过了核心硬件-CPU.我们在选购独立显卡的时候,通常小白只看显存大小,其实这是最大的选购误区,然而决定显卡的性能不 ...
- 09-如何选购台式电脑电源?小白装机通俗易懂的电脑电源选购知识指南
电源虽然不影响一台电脑的性能,但是它决定了电脑的稳定性,电源相当于人体的心脏,给电脑各个部件提供合适的稳定电压,选购电源的重要性至关重要,不过大多数用户往往会忽视电源的重要性.那么如何选购台式电脑电源 ...
- 台式计算机显示器,显示器基础知识:通俗易懂的台式电脑显示器知识
对于DIY装机,我们选购显示器只看尺寸大小和外观,而显示器的参数都往往被忽视,其实选择显示器也是有讲究了,不只是看看大小和外观那么简单.下面装机之家分享一下显示器基础知识,使用通俗易懂的方式介绍台式电 ...
- Scala基础知识(个人总结)
声明: 1. 本文为我的个人复习总结, 并非那种从零基础开始普及知识 内容详细全面, 言辞官方的文章 2. 由于是个人总结, 所以用最精简的话语来写文章 ...
- Scala基础知识笔记2
1 类 1.1 定义一个简单的类 1.2 field的getter 和 setter方法 感觉成员变量定义成 var 属性名=属性值即可, 不需要定义成 val 或者 private就行, // ...
- 计算机科学与技术初级知识,计算机科学与技术专业课程有哪些
计算机科学与技术专业课程有哪些2021-06-15 14:18:02文/李文源 数字电路.计算机系统结构.算法.程序设计语言.软件工程.并行分布计算.智能技术.计算机图形学与人机交互等知识领域的基本内 ...
最新文章
- 14、四大组件--Service
- c/c++ 获取文件夹或目录下的文件
- To-do-List
- 网络中pkt是什么意思_网络流行语Cp、磕么?是什么意思?
- 卸载MySQL以及重装卡到Start Services的解决办法(亲测有效,刚重装成功)
- 更轻松的获取APK文件安装时间
- mysql手机号段地区库_最新全国手机号段归属地数据库下载(mysql+xlsx+txt格式)46万条...
- CISSP国际注册信息系统安全专家
- 图像降噪有哪些方法?
- 如何修改网络连接的网络位置
- 二月(不积跬步无以至千里)
- 三十岁以后,我一定能阔起来!
- shopify 与国内第三方建站服务平台的比较(店匠、shopline、shopyy、ueeshop)
- INFOR WMS仓储管理系统里常用表说明
- Mob研究院 |2019互联网医疗行业洞察
- P1873 [COCI 2011/2012 #5] EKO / 砍树
- stm32的语音识别_基于STM32的嵌入式语音识别模块设计实现
- md5压缩函数用java实现,MD5压缩算法介绍
- Python爬虫实战之爬取网站全部图片(二)
- C# Pdf添加页码(iTextSharp)
热门文章
- 小学四年级计算机制作月历教案,小学信息技术教案制作月历
- 荧光素FITC标记多糖,FITC-polysaccharide
- uniapp取消网络请求
- halfstone 原理_half of --中的一半.当它所指代的是不可数名词时.代表单数.如果half of 后边所接的是可数名词的复数.那么它所代表的也是复数概念....
- Unity HDRP示例场景解析
- AS3及FLEX百条常识
- linux下安装7z命令及7z命令的使用
- 转 光线追踪的基本原理
- 多层PCB主要制作难点,PCB工程师了解一下很有必要!
- 试图将驱动程序添加到存储区_新版Wii U模拟器CEMU 1.15.1将发布 提供众多改进