Scala学习--day01变量与数据类型、运算符

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: Scala学习--day01变量与数据类型、运算符

Scala语言入门

Scala(发音为/ˈskɑːlə, ˈskeɪlə/)是一门多范式的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。洛桑联邦理工学院的Martin Odersky于2001年基于Funnel的工作开始设计Scala。Java平台的Scala于2003年底/2004年初发布。

特点:

  • 同样运行在JVM上,可以与现存程序同时运行。
  • 可直接使用Java类库。
  • 同Java一样静态类型。
  • 语法和Java类似,比Java更加简洁(简洁而并不是简单),表达性更强。
  • 同时支持面向对象、函数式编程。
  • 比Java更面向对象。

关注点:

  • 类型推断、不变量、函数式编程、高级程序构造。
  • 并发:actor模型。
  • 和现有Java代码交互、相比Java异同和优缺。

和Java关系:

javac               java
.java --------> .class ----------> run on JVM
.scala -------> .class ----------> run on JVM
        scalac              scala

测试代码:Scala分支

阅读:

环境配置

Scala需要依赖Java,访问这里查看特定Scala版本依赖的Java版本。这里选择,最新的JDK17配合Scala2.13.6。

Windows中下载安装配置环境变量:

  • 类似于java配置SCALA_HOME为安装目录。
  • 添加%SCALA_HOME%\bin到path环境变量。

Linux中类似,可以使用包管理器,但如果依赖版本不严格一致的话,需要官网下载对应版本安装即可。

也有交互式执行环境:

scala

交互式执行环境中的传统艺能:

println("hello,world!")

暂时不管项目配置,还是单文件编译执行为主,项目开发肯定要以包的形式组织可以使用IntelliJ IDEA开发,使用maven或者sbt进行项目配置。

使用VSCode编辑器,安装插件Scala Syntax (official)和Scala (Mentals)。

新建文件HelloScala.scala

object HelloScala { // HelloScala is a object, not a class, will create a

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

       println("hello,world!");

   }

}

可以使用插件CodeRunner直接快捷键运行。也可以在命令行编译为字节码后再运行:

scalac HelloScala.scala
scala helloScala

或者直接运行scala源文件:

scala HelloScala.scala

和java如出一辙。

如果编译的话会生成2个.class字节码文件,HelloScala.classHelloScala$.class。都是字节码但是不能通过java直接运行。但对于HelloWorld这个例子来说,java源代码编译而成的字节码是可以通过scala命令运行的。

原因是没有引入Scala的库,添加classpath就可以通过java执行scala编译成的字节码了:

java -cp %SCALA_HOME%/lib/scala-library.jar; HelloScala

使用Java Decompiler反编译字节码到java源文件可以看到引入Scala库的逻辑。并且:

  • scala源文件中的HelloScala对象编译后成为了一个类,但对象本身编译后就是生成的另一个类HelloScala$类的单例对象HelloScala$.MODULE$,称之为伴生对象。
  • HelloScala$有一个main实例方法,HelloScala类的静态方法通过这个单例对象转调这个实例方法。完成打印。
  • Scala比Java更面向对象。

IDEA环境配置

使用IntelliJ IDEA:

  • 创建Maven项目,JDK版本17。
  • 安装插件:Scala。一般默认都已经装了。
  • Maven项目默认用Java写,在main/目录下新建目录scala/,然后将目录标记为Source Root。
  • 这样甚至可以在同一个项目中混用Scala和Java源文件,并互相调用。
  • 需要能够添加scala源文件,右键项目,添加框架支持,配置Scala SDK,选择,然后就可以右键添加Scala源文件了。
  • 添加包,添加Scala类,选择对象,编辑源码。
package chapter01
//object:关键字,声明一个单例对象(伴生对象)
object HelloWord {
  /*main方法:从外部可以直接调用执行方法
  * def 方法名(参数名称:参数类型):方法返回值类型={方法体}
  * */
  def main(args: Array[String]): Unit = {
    System.out.println("hhaha")
    println("Hello scala")
  }

}
  • Ctrl + Shift + F10运行。
  • 可以看到执行的命令是javaclasspath中引入了Scala的jar包形式的库。
  • 调用java的类库:
package VeryStarted
object HelloWorld {
  def main(args: Array[String]): Unit= {
    println("Hello,world!")
    System.out.println("Hello,world! from java")
  }
}

语法含义:

object SingletonObject { body }

def MethodName(ArgName: ArgType): RetType = { body }

object关键字创建的伴生对象,可以理解为替代Java的static关键字的方式,将静态方法用单例对象的实例方法做了替代,做到了更纯粹的面向对象。

仅仅测试理解语法既可以单文件编写VSCode编译执行也可以用IDEA管理项目,影响不大。

再用一个等价的类定义来认识和区别一下Scala和Java:

image.png

image.png

java:

public class Student {
    private String name;
    private Integer age;
    private static String school = "XDU";
    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public void printInfo() {
        System.out.println(this.name + " " + this.age + " " + Student.school);
    }
    // psvm
    public static void main(String[] args) {
        Student tch = new Student("tch", 20);
        tch.printInfo();
    }
}

scala:

package VeryStarted
class Student(name: String, age: Int) {
  def printInfo(): Unit = {
    println(name + " " + age + " " + Student.school)
  }
}
// 引入伴生对象,名称一致,同一个文件
object Student {
  val school: String = "XDU"
  def main(args: Array[String]): Unit = {
    val tch = new Student("tch", 20)
    tch.printInfo()
  }
}

Scala库源码与API文档:

  • 官网上下载下载Scala源码,解压到Scala安装目录或任意位置。
  • IntelliJ IDEA进入反编译的源码后选择右上角附加源码,选择源码的src/目录。
  • 安装包里面已经有了文档,没有的话可以单独下载。
  • Scala依赖Java,某些类型就是Java的包装,库中有一部分java源码。

变量与数据类型

注释:

  • 和java一样
  • // 单行
  • /* */ 多行
  • /** */ 文档,方法或者类前面,便于scaladoc生成文档。

变量和常量:

var | val 变量名 :变量类型 = 变量值

var name [:VariableType] = value // variable

val name [:ConstantType] = value // constant

因为Scala的函数式编程要素,所以一个指导意见就是能用常量就不要用变量。

  • 声明变量时,类型可以省略,编译器会自动推导。
  • 静态类型,类型经过给定或推导确定后就不能修改。
  • 变量和常量声明时,必须有初始值。
  • 变量可变,常量不可变。
  • 引用类型常量,不能改变常量指向的对象,可以改变对象的字段。
  • 不以;作为语句结尾,scala编译器自动识别语句结尾。

标识符命名规范:

  • 字母下划线开头,后跟字母数字下划线,和C/C++/Java一样。
  • 操作符开头,且只包含(+-*/#!等),也是有效的标识符。这样用会用什么奇怪的好处吗?答案是灵活到天顶星的运算符重载。
  • 用反引号包括的任意字符串,即使是同39个Scala关键字同名也可以。有点奇怪的用法,尚不知道为什么。

var _abc:String = "hello"

val -+/%# = 10

val `if` = 10

println(_abc)

println(-+/%#)

println(`if`)

关键字:

  • package import class obejct trait extends with type for
  • private protected abstract sealed final implicit lazy override
  • try catch finlly throw
  • if else match case do while for return yield
  • def var val
  • this super
  • new
  • true false null
  • 其中Java没有的关键字:object trait with implicit match yield def val var

字符串:

  • 类型:String
  • +号连接
  • *字符串乘法,复制一个字符串多次
  • printf格式化输出
  • 字符串插值:s"xxx${varname}"前缀s模板字符串,前缀f格式化模板字符串,通过$获取变量值,%后跟格式化字符串。
  • 原始字符串:raw"rawstringcontents${var}",不会考虑后跟的格式化字符串。
  • 多行字符串:""" """
  • 输出:print printf println ...
package String
//传值字符串
object ScalaSt {
  def main(args: Array[String]): Unit = {
    //字符串,通过+号连接
    val name:String="alice"
    val age:Int=18
    println(age+"岁的"+name+"在尚硅谷学习")
    //*用于将一个字符串重复拼接
    println(name*3)
    //传值字符串,通过%传值
    print("%d岁的%s在尚硅谷学习",age,name)
    println()
    //插值字符串 :通过$获取变量值
    println(s"${age}岁的${name}在尚硅谷学习")
    //格式化模板代码
    val num:Double=2.3453
    println(f"The num is ${num}%2.2f")
    println(f" : power ${num}%.2f.")
    //三引号表示字符串,保持多行字符串的原始输出
    s"""
       |select*
       |from
       |student
       |where
       |name=${name}
       |and
       |age>${age}
       |""".stripMargin
  }

}

输入:

  • StdIn.readLine()
  • StdIn.readShort() StdIn.readDouble
  • import scala.io.StdIn
package String
import scala.io.StdIn
object StdInr {
  def main(args: Array[String]): Unit = {
    //输入信息
//    val str = StdIn.readLine("请输入您的大名: ")
//    val str1 = StdIn.readLine("请输入您的年龄: ")
//    val name = StdIn.readLine()
//    val age=StdIn.readInt()
//    println(s"欢迎${age}岁的${name}来到尚硅谷学习")
    println("input name:")
    val name: String = StdIn.readLine()
    println("input age:")
    val age: Int = StdIn.readInt()
    println(s"欢迎${age}岁的${name}来到尚硅谷学习")

读写文件:

package String

import java.io.{File, PrintWriter}
import scala.io.Source

object FileIO {
  def main(args: Array[String]): Unit = {
    //1.从文件中读取数据(绝对路径)
    Source.fromFile("F:\\scala代码\\scala_tut\\src\\main\\resources\\test.txt").foreach(print)
    //2.将数据写入文件
    val writer = new PrintWriter(new File("F:\\scala代码\\scala_tut\\src\\main\\resources\\test.txt"))
    writer.write("hello scala from java writer")
    writer.close()
  }

}

image.png

数据类型:

  • java基本类型char byte short int long float double boolean
  • java引用类型:Object,数组,字符串,包装类,集合,POJO对象等(对象类型)
  • java基本类型对应包装类型:Charater Byte Short Integer Long Float Double Boolean
  • java中不是纯粹的面向对象。
  • Scala吸取了这一点,所有数据都是对象,都是Any的子类。
  • Any有两个子类:AnyVal值类型 AnyRef引用类型。
  • 数值类型都是AnyVal子类,和Java数值包装类型都一样,只有整数在scala中是Int、字符是Char有点区别。
  • StringOps是java中String类增强,AnyVal子类。
  • Unit对应java中的voidAnyVal子类。用于方法返回值的位置,表示方法无返回值,Unit是一个类型,只有一个单例的对象,转成字符串打印出来为()
  • Void不是数据类型,只是一个关键字。
  • Null是一个类型,只有一个单例对象null就是空引用,所有引用类型AnyRef的子类,这个类型主要用途是与其他JVM语言互操作,几乎不在Scala代码中使用。
  • Nothing所有类型的子类型,也称为底部类型。它常见的用途是发出终止信号,例如抛出异常、程序退出或无限循环。

Scala数据类型

Scala是完全面向对象的语言,所以不存在基本数据类型的概念,有的只是任意对象类型(AnyVal)和任意引用对象类型(AnyRef)

image.png

空集是所有集合的子集

image.png

整数类型:都是有符号整数,标准补码表示。

  • Byte 1字节
  • Short 2字节
  • Int 4字节
  • Long 8字节
  • 整数赋初值超出表示范围报错。
  • 自动类型推断,整数字面值默认类型Int,长整型字面值必须加L后缀表示。
  • 直接向下转换会失败,需要使用强制类型转换,(a + 10).toByte

浮点类型:

  • Float IEEE 754 32位浮点数
  • Double IEEE 754 64位浮点数
  • 字面值默认Double

字符类型:

  • 同java的Character,2字节,UTF-16编码的字符。
  • 字符常量:''
  • 类型Char
  • 转义:\t \n \r \\ \" \'etc

布尔类型:true false

空类型:

  • Unit 无值,只有一个实例,用于函数返回值。
  • Null 只有一个实例null,空引用。
  • Nothing 确定没有正常的返回值,可以用Nothing来指定返回值类型。好像意思是抛异常时返回Nothing,不是特别懂。
object NullType {
    def main(arg : Array[String]) : Unit = {
        // Unit
        def f1(): Unit = {
            println("just nothing!")
        }
        val a = f1()
        println(a) // ()
        // null only used for AnyRef 空引用NuLL
        // val n:Int = null // invalid
        //所有类对应的应用类型
      //var student:Student=new Student("alice",20)
      student=null
      println(student)
      //Nothing
      def m2(n:Int):Int={
        if(n==0)
            throw new NullPointException
        else
          return n
      }
      val b=m2(0)
      println(b)
      
    }
}

数据类型转换:

  • 自动类型提升:多种数据类型混合运算,自动提升到精度最大的数据类型。
  • 高精度赋值到低精度,直接报错。
  • 除了图中的隐式类型转换,都需要强制类型转换。
  • Byte Short Char计算时会直接提升为Int
  • Boolean不能参与整数浮点运算,不能隐式转换为整数。

强制类型转换:

  • toByte toInt toChar toXXXX
  • 'a'.toInt 2.7.toInt
  • 数值与String的转换:"" + n "100".toInt "12.3".toFloat 12.3".toDouble.toInt
  • 整数强转是二进制截取,整数高精度转低精度可能会溢出,比如128.toByte

Scala标准库:

  • Int Double这些数据类型对应于Java中的原始数据类型,在底层的运行时不是一个对象,但Scala提供了从这些类型到scala.runtime.RichInt/RichDouble/...的(低优先级)隐式类型转换(在Perdef中定义),从而提供了非原始类型具有的对象操作。
  • 基本类型都是默认导入的,不需要显式导入,位于包scala中。还有scala.Predef对象也是自动导入。
  • 其他需要导入的包:
  • scala.collection集合。
  • scala.collection.immutable不可变数据结构,比如数组、列表、范围、哈希表、哈希集合。
  • scala.collection.mutable可变数据结构,数组缓冲、字符串构建器、哈希表、哈希集合。
  • scala.collection.concurrent可变并发数据结构,比如字典树。
  • scala.concurrent原始的并发编程。
  • scala.io输入输出。
  • scala.math基本数学操作。
  • scala.sys操作系统交互。
  • scala.util.matching正则。
  • 标准库中的其他部分被放在独立的分开的库中。可能需要单独安装,包括:
  • scala.reflect反射API。
  • scala.xmlxml解析、操作、序列化。
  • scala.collection.parallel并行集合。
  • scala.util.parsing parser的组合子,什么东西?
  • scala.swingjava的GUI框架Swing的封装。
  • 定义了一些别名给常用的类,比如Listscala.collection.immutable.List的别名,也可以理解为默认导入?
  • 其他别名可能是底层平台JVM提供的,比如Stringjava.lang.String的别名。

强转溢出面试题

package String
//128:int类型 ,占据4个字节,32字节
//1000 0000
//原码: 0000 0000 0000 0000 0000 0000 1000 0000
//补码 : 0000 0000 0000 0000 0000 0000 1000 0000
//截取最后一个字节,byte
/*得到补码 1000 0000
表示最大负数 -128
* */


//130:int类型 ,占据4个字节,32字节
//1000 0000
//原码: 0000 0000 0000 0000 0000 0000 1000 0010
//补码 : 0000 0000 0000 0000 0000 0000 1000 0010
//截取最后一个字节,byte
/*得到补码 1000 0010
原码  1111 1110
表示最大负数 -126
* */
object TestType {
  def main(args: Array[String]): Unit = {
    var n:Int = 128
    var b:Byte=n.toByte
    println(b)
  }

}

运算符

运算符:

  • 和Java基本相同。
  • 算术运算:+ - * / %+可以用于一元正号,二元加号,还可以用作字符串加法,取模也可用于浮点数。没有自增和自减语法++ --
  • 关系运算:== != < > <= >=
  • 逻辑运算:&& || !&& ||所有语言都支持短路求值,scala也不例外。
  • 赋值运算:= += -= *= /= %=
  • 按位运算:& | ^ ~
  • 移位运算:<< >> >>>,其中<< >>是有符号左移和右移,>>>无符号右移。
  • scala中所有运算符本质都是对象的方法调用,拥有比C++更灵活的运算符重载。

自定义运算符:

  • Scala中运算符即是方法,任何具有单个参数的方法都可以用作中缀运算符,写作中缀表达式的写法。10.+(1)即是10 + 1
  • 定义时将合法的运算符(只有特殊符号构成的标识符)作为函数名称即可定义。

运算符优先级:

  • 当一个表达式使用多个运算符时,将根据运算符的第一个字符来评估优先级。内置的运算符和自定义运算符都是函数,遵守同样的规则。

(characters not shown below)

* / %

+ -

:

= !

< >

&

^

|

package 运算符

object Operator {
  def main(args: Array[String]): Unit = {
    //1.算术运算符
    val result:Int=10/3
    println(result)
    val result1: Double = 10 / 3
    println(result1)
    val result2: Double = 10.0 / 3 强转过程的精度缺失二进制
    println(result2)
        val result3: Double = 10.0 / 3
    println(result3.formatted("%5.2f"))

    
  }

}

image.png

java比较运输运算符==

package 运算符;

public class test {
    public static void main(String[] args) {
        String s1="hello";
        String s2=new String("hello");
        boolean b = s1 == s2;  //比较的是引用地址
        System.out.println(b);  false
        System.out.println(s1.equals(s2)); //比较的是内容  true
    }
}
object Operator {
  def main(args: Array[String]): Unit = {
    //1.算术运算符
    val result:Int=10/3
    println(result)
    val result1: Double = 10 / 3
    println(result1)
    val result2: Double = 10.0 / 3
    println(result2)
    val result3: Double = 10.0 / 3
    println(result3.formatted("%5.2f"))
    //2.比较运算符
    val s1:String="hello"
    val s2:String=new String("hello")
    println(s1==s2)  //true
    println(s1.equals(s2)) //true
    //引用地址比较
    println(s1.eq(s2))  //false
  }

}
    //3.逻辑运算符
    def m(n:Int):Int={
      println("m被调用了")
      return n
    }
    val n=1
    //短路与
    println((4>5)&&m(n)>1)
    //判断一个字符串是否为空
    def isNotEmpty(str:String):Boolean={
      return str!=null && !("".equals(str.trim))
    }
    println(isNotEmpty(null))  //false
 //赋值运算符
        //自增自减
        int x=15;
        int y=x++;
        System.out.println(x+","+y);   //16,15
        x=15;
        y=++x;
        System.out.println(x+","+y); //16,16
        x=23;
        y=x++;
        System.out.println(x);  //temp=x++ x=tmp 23
var b:Byte=10
var i:Int=12
i+=1
println(i)
//没有i++的写法scala中

Scala中其实是没有运算符的所有运算符都是方法。

scala是完全面向对象的语言,所以数字其实也是对象

 当调用对象的方法时,点.可以省略

 如果函数参数只有一个,或者没有参数,()可以省略





相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
2月前
|
IDE Java 编译器
scala的两种变量类型 var 和 val
scala的两种变量类型 var 和 val
73 2
scala的两种变量类型 var 和 val
|
2月前
|
Scala 容器
Scala学习--day04--集合、常用方法、案例实操 - WordCount TopN、不同省份的商品点击排行
Scala学习--day04--集合、常用方法、案例实操 - WordCount TopN、不同省份的商品点击排行
|
2月前
|
消息中间件 分布式计算 大数据
Scala学习--day03--函数式编程
Scala学习--day03--函数式编程
|
2月前
|
Java Scala
Scala学习--day02---控制流、“九层妖塔—杨辉三角”
Scala学习--day02---控制流、“九层妖塔—杨辉三角”
117 1
|
2月前
|
存储 Scala
Scala变量和数据类型
Scala变量和数据类型
35 1
|
1月前
|
分布式计算 资源调度 Java
Scala+Spark+Hadoop+IDEA实现WordCount单词计数,上传并执行任务(简单实例-下)
Scala+Spark+Hadoop+IDEA实现WordCount单词计数,上传并执行任务(简单实例-下)
26 0
|
1月前
|
分布式计算 Hadoop Scala
Scala +Spark+Hadoop+Zookeeper+IDEA实现WordCount单词计数(简单实例-上)
Scala +Spark+Hadoop+Zookeeper+IDEA实现WordCount单词计数(简单实例-上)
20 0
|
2月前
|
SQL 存储 分布式计算
在scala中使用spark
在scala中使用spark
58 0
|
2月前
|
分布式计算 Java Scala
spark 与 scala 的对应版本查看、在idea中maven版本不要选择17,弄了好久,换成11就可以啦
spark 与 scala 的对应版本查看、.在idea中maven版本不要选择17,弄了好久,换成11就可以啦
211 2