最通俗易懂的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.名词介绍

JavaScala
Interfacetraits
枚举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 C

val 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 y
    def unit: String = ""
  }
  
  /* 创建了一个int类型的对象 */
  implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
  	/* 对这里面的两个方法做了实现 */
    def add(x: Int, y: Int): Int = x + y
    def 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.unit
    else 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.say
    var 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.eat
    p1.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_02
    base_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 ) 
    
     
  }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值