美文网首页
快学scala 1-5章

快学scala 1-5章

作者: sadamu0912 | 来源:发表于2019-06-16 11:49 被阅读0次

scala for循环跳出

1 嵌套函数

object TestClient extends App {
  var res =0;
  def forOuter={

    def forInner {
      for(i<- 0 until 10 ){
        if (i==5){return}
        res += i
      }
    }
    forInner
    res
  }
  forOuter
  print(res)
}

嵌套函数,就是外面包一层,然后里面有函数定义其中函数的定义是自己调用自己,也有函数的调用。也就是函数的递归调用需要我们去包装一层。而不是直接调用。

注意 forInner 后面没有=号,表示没有返回值,有等号表示有返回值,加了=号,return会报错

2 高级for循环 ,if守卫,这里其实是循环终止有两个条件判断,一个是i<10,一个是flag=true

object TestClient extends App {
  var flag = true
  var res = 0

  for (i <- 0 until 10 if flag) {
    res += i
    if (i == 4) flag = false
  }
  println(res)
}

可以用变量<- 表达式 提供多个生成器,分号隔开,每个生成器都可以带一个守卫。比如
for (i<- 1 to 3 ;j<- 1to 3 if i!=j )

使用breakable代码块

3、使用Breaks类的break方法
跟java里面的break比较类似,相对来说,比较灵活好用;与breakable代码块配合使用

import scala.util.control.Breaks._

var res = 0

breakable {
  for (i <- 0 until 10) {
    if (i == 5) {
      break;
    }
    res += i
  }
}

for 推导式

for (i<- 0to 10 ) yield i*2
抽象出来就是for list yield x的expression

object TestClient extends App {
 lazy val words = scala.io.Source.fromFile("D:\\maven-settings-public.xml").mkString
  println(words)
}

数组和数组缓冲

 import scala.collection.mutable.Buffer
  import scala.collection.mutable.ArrayBuffer
  import scala.collection.JavaConversions.bufferAsJavaList
object TestClient extends App {
  val b = new ArrayBuffer[Int]
  b +=1   //末尾添加元素
  b += (2,3,4)  //添加集合,用括号括起来
  b ++= Array(12,-1,5)   //++=添加任何集合
  b.insert(2,6)
  b.remove(2)
  b.insert(3,-5)
  b.insert(4,-12)
  var first =true
  //拿到正数和第一个负数,其他去掉
 val indexes =  for(i<-0 until b.length if first||b(i)>0) yield {if(b(i)<0) first=false;i}
  for(j<-0 until indexes.length) b(j) = b(indexes(j))
  b.trimEnd(b.length-indexes.length)
  for(item<- b) println(item)
  //java 和scala互相转化  就是两套系统的相互转化
  //ArrayBuffer===>List(java的方法需要入参是List,直接把ArrayBuffer转成List)
    val command =  ArrayBuffer("ls","-al","/home/ssy")
    val pb = new ProcessBuilder(command)
  //当java的返回值是List,scala需要转化换成ArrayBuffer
  import scala.collection.JavaConversions.asScalaBuffer
  val cmd:Buffer[String] = pb.command()

}

class Person{
 var age=0
def increment()={age+=1}
def current()={age}
}
class Person{
 private  var age=0
def increment()={age+=1}
def current()={age}
}
class Person{
 protected var age=0
def increment()={age+=1}
def current()={age}
}

分别编译之后

scalac Person.scala
javap -private Person.class

public class Person {  //public (default)
  private int age;
  public int age();
  public void age_$eq(int);
  public void increment();
  public int current();
  public Person();
}

public class Person {  //private
  private int age;
  private int age();
  private void age_$eq(int);
  public void increment();
  public int current();
  public Person();
}

public class Person {   //protected
  private int age;
  public int age();
  public void age_$eq(int);
  public void increment();
  public int current();
  public Person();
}
//当age是val变量时
public class Person {
  private final int age;
  public int age();
  public int current();
  public Person();
}


可以发现,不论变量到底是private,protected ,public 都会有private的变量。如果是protected和public就会有public的get/set方法 age和age_=,这里的下划线,理解成占位符。有一些东西,但是不知道是什么

如果age变量是val的话,那就是只有get方法了,因为val不可变。
如果不需要get/set方法,就生明为private[this](只能自己对象访问自己对象,即使同一个类的对象也不行,但是外部类的变量可以访问)

scala中的变量,包括属性和get/set方法

如果需要java版本的get/set方法。

import scala.beans.BeanProperty
class Person{
@BeanProperty  var age = 0
def current()={age}
}

编译之后:

public class Person {
  private int age;
  public int age();
  public void age_$eq(int);
  public int current();
  public int getAge();
  public void setAge(int);
  public Person();
}

主构造器就是把类的定义也看做是函数的定义。糅合在一起。
辅助构造器名称是this。每个辅助构造器,要先调用主构造器或者前面定义过的辅助构造器。
构造器虽然也可以看做是函数的定义,但是有个特点,就是方法签名后面不跟=号,而是直接跟方法体

class Person{
  private var name = ""
  private var age = 0
  def this(name:String) {
    this()
    this.name = name
  }
  def this(name:String,age:Int){
    this(name)
    this.age =age 
  }
}

嵌套类以及类型投影

scala有一种类型叫路径依赖类型,比如外部类Outer,内部类Inner。
inner1 = new outer1.InnerClass
和java不同的是,java只认类型,类型和具体实例无关。
那问题来了,怎么让外部类的方法,接受另外一个实例的内部类作为方法参数呢。
答案就是用类型投影

class Outter{

    public class Inner {}

    public void foo(Inner c){
        System.out.println(c);
    }
}

public class Main {
    public static void main(String[] args)throws Exception{
        Outter o1 = new Outter();
        Outter o2 = new Outter();
        Outter.Inner i1 = o1.new Inner();
        Outter.Inner i2 = o2.new Inner();
        o1.foo(i2);
    }
}

创建Inner实例,只是和Outer.Inner i1 = o1.new Inner();

object TypeProjection extends App{
  val outter1 = new OutterClass
  outter1.getName("电脑")
  val inner1 = new outter1.InnerClass
  inner1.getName("主机")
  println(outter1)

  val outter2 = new OutterClass
  outter2.getName("洗衣机")
  val inner2 = new outter2.InnerClass
  inner2.getName("滚筒")
  println(outter2)
  println("==============无类型投影=================")
  //如果我想把洗衣机的滚筒这个内部类放到电脑这里的getInner方法里
  outter1.getInner(inner1)//放自己的没问题,也没意义的样子
  //outter1.getInner(inner2)
  println("==============类型投影=================")
  outter1.getInner2(inner2)//新添加一个类型投影就可以了

}

/**
  * 外部类,内部类其实是外部类的一个成员,不像JAVA一样
  */
class OutterClass{
  outter =>
  var name: String = _
  def getName(getname: String): Unit ={
    this.name = getname
  }
  def getInner(innerClass: InnerClass) = {
    println("innerClass'name is " + innerClass.name)//调用内部类成员
    println("I'm a " + name + "!!!I'm aloof")
  }

  def getInner2(innerClass: OutterClass#InnerClass) = {
    println("innerClass'name is" + innerClass.name)//调用内部类成员
    println("I'm a " + name + " !!!I'm aloof")
  }

  /**
    * 内部类
    */
  class InnerClass{
    inner =>
    var name: String = _
    def getName(getname: String): Unit ={
      this.name = getname
    }
    def say: Unit ={
      println("outterClass is  " + outter.name)//调用外部类成员
      print("I'm a Innerclass!!!I'm proud")
    }
  }
}

在scala里,内部类型(排除定义在object内部的),想要表达所有的外部类A实例路径下的B类型,即对 a1.B 和 a2.B及所有的 an.B类型找一个共同的父类型,这就是类型投影,用 A#B的形式表示。

对象object

object Accounts {

  private var lastNumber = 0

  /**
    * 定义一个getNumber的方法
    *
    * @return
    */
  def getNumber(): Int = {
    lastNumber += 1
    lastNumber
  }

  def main(args: Array[String]): Unit = {
    // 相当于java静态方法调用
   println(Accounts.getNumber())
  }

编译之后,生成两个class文件一个是Account.class一个是Account$.class

public final class Accounts {
  public static void main(java.lang.String[]);
  public static int getNumber();
}
public final class Accounts$ {
  public static Accounts$ MODULE$;
  private int lastNumber;
  public static {};
  private int lastNumber();
  private void lastNumber_$eq(int);
  public int getNumber();
  public void main(java.lang.String[]);
  private Accounts$();
}

我们发现Accounts$是一个单例模式的,构造器私有化。然后Accounts 里面都是静态的方法。所以我们静态调用访问的应该是这个类。而且两个都是final类。
我们再加上伴生对象试试

object Account{
  //可以互相访问私有变量指的是可以点出来,前提是有对象
  def print(a:Account):Unit={println(a.lastNumber)}
}
class Account {

   private var lastNumber = 0

  /**
    * 定义一个getNumber的方法
    *
    * @return
    */
  def getNumber(): Int = {
    lastNumber += 1
    lastNumber
  }

  def main(args: Array[String]): Unit = {
    // 相当于java静态方法调用
   val number = new Account().getNumber()
    println(lastNumber)
  }

}

编译之后,两个class文件

public class Account {
  private int Account$$lastNumber;
  public static void print(Account);
  public int Account$$lastNumber();
  private void Account$$lastNumber_$eq(int);
  public int getNumber();
  public void main(java.lang.String[]);
  public Account();
}
public final class Account$ {
  public static Account$ MODULE$;
  public static {};
  public void print(Account);
  private Account$();
}

辅助构造器

1 名称是this. 而且必须以主构造器的调用或者用已经定义的辅助构造器调用为先。
主构造器的参数会被编译成字段。

class Constructor2 {
  println("just a tip")
}
object Test3 {
  def main(args: Array[String]): Unit = {
    val cons = new Constructor2();
  }
}
//输出just a tip

主构造器会定义了构造器中的所有语句。

相关文章

网友评论

      本文标题:快学scala 1-5章

      本文链接:https://www.haomeiwen.com/subject/alvkxctx.html