1. 程式人生 > >scala習題(11)——操作符

scala習題(11)——操作符

scala操作符優先順序
*/%
+-
:
<>
!=
&
^
|-
非操作符
最低優先順序賦值操作符
從高到低優先順序逐漸降低,同一層屬同等優先順序,按照從左到右的順序進行計算(除了以冒號結尾的操作符和賦值操作符)

1.根據優先順序規則,3+4 ->5 和 3 ->4+5是如何被求值的
(3+4 ->5)因為+號和->號的優先順序在同一層次上(組合操作符按照組合中的最高級別操作符來定義優先順序,+,-號在同一層,所以優先順序一樣),所以按照從左到右的運算方式來運算即為(7,5)
第二個算式存在問題,不能直接這麼加減,因為元組和int相加時會先轉換成字串,而5的型別並不是字串,直接repl中輸入就會上報一個type missmatch的錯誤

2.BigInt類有一個pow方法,但沒有用操作符字元。Scala類庫的設計者為什麼沒有選用**(像Fortran那樣)或者^(像Pascal那樣)作為乘方操作符呢?

一般乘方的操作符是優於乘法操作的,如果使用**作為乘方的話,那麼其優先順序則與*相同,而如果使用^的話則屬於非操作符,則優先順序低於*操作。優先順序都是有問題的。故沒有使用這兩種操作符

3.實現Fraction類,支援+*/操作。支援約分,例如將15/-6變為-5/2。除以最大公約數,像這樣:

class Fraction(n:Int,d:Int){
    private val num:Int = if(d==0) 1
else n * sign(d)/gcd(n,d); private val den:Int = if(d==0) 0 else d * sign(d)/gcd(n,d); override def toString = num + "/" + den def sign(a:Int) = if(a > 0) 1 else if (a < 0) -1 else 0 def gcd(a:Int,b:Int):Int = if(b==0) abs(a) else gcd(b,a%b) ... }
class Fraction(n:Int,d:Int){
      private
val num:Int = if(d==0) 1 else n * sign(d)/gcd(n,d); private val den:Int = if(d==0) 0 else d * sign(d)/gcd(n,d); override def toString = num + "/" + den def sign(a:Int) = if(a > 0) 1 else if (a < 0) -1 else 0 def gcd(a:Int,b:Int):Int = if(b==0) abs(a) else gcd(b,a%b) def +(other:Fraction):Fraction={ new Fraction((this.num*other.den+this.den*other.num),this.den*other.den); } def -(other:Fraction):Fraction={ new Fraction((this.num*other.den-this.den*other.num),this.den*other.den); } def *(other:Fraction):Fraction={ new Fraction((this.num*other.num),this.den*other.den); } def /(other:Fraction):Fraction={ new Fraction((this.num*other.den),this.den*other.num); } } object Fraction { def apply(n:Int,d:Int):Fraction={ new Fraction(n,d); } def unapply(input:Fraction):Option[(Int,Int)]={ if(input.den==0) None else Some((input.num,input.den)); } }
  1. 實現一個Money類,加入美元和美分欄位。提供+,-操作符以及比較操作符==和<。舉例來說,Money(1,75)+Money(0,50)==Money(2,25)應為true。你應該同時提供*和/操作符嗎?為什麼?

不需要提供,因為對於金額來說,乘除並沒有意義

class Money(y:Int,f:Int){
    private val yuan:Int= if(f<100&&f>=0) y else if(f>=100) y+f/100 else { if(abs(f)>=100) y-abs(f)/100 else y-1};
    private val fen:Int=if(f<100&&f>=0) f else if(f>=100) f%100 else { if(abs(f)>=100) abs(f)/100*100+f else f+100};
    def +(other:Money):Money={
      new Money(this.yuan+other.yuan,this.fen+other.fen);
    }
    def -(other:Money):Money={
     if(this>other){
      new Money(this.yuan-other.yuan,this.fen-other.fen);
     }else{
       println("not much money");
       null
     }
    }
    def >(other:Money):Boolean={
      if(this.yuan>other.yuan){
        true;
      }else if(this.yuan<other.yuan){
        false
      }else{
        if(this.fen>other.fen) true else false;
      }

    }
    def <(other:Money):Boolean={
      if(this.yuan<other.yuan){
        true;
      }else if(this.yuan>other.yuan){
        false
      }else{
        if(this.fen>other.fen) false else true;
      }

    }
    override def toString()="yuan:"+yuan+" fen:"+fen;
  }
  object Money{
    def apply(y:Int,f:Int):Money={
      new Money(y,f);
    }
  }
  1. 提 供操作符用於構造HTML表格。例如:Table() | “Java” | “Scala” || “Gosling” | “Odersky” || “JVM” | “JVM,.NET”應產出:
    JavaScala
    Gosling…
    注意操作符無論何時都是針對於物件來說的,所以要返回的資料只能是該物件
 class Table{
    var s:String="";

    def |(txt:String):Table={
      s=s+"<td>"+txt+"</td>";
      this;
    }
    def ||(txt:String):Table={       
        s=s+"</tr>"+"<tr><td>"+txt+"</td>";
        this;
    }
    override def toString="<table><tr>"+s+"</tr></table>";
  }
  object Table{
    def apply():Table={
      new Table();
    }
  }

6.提供一個ASCIIArt類,其物件包含類似這樣的圖形:
/_/\
( ’ ’ )
( - )
| | |
(|)
提供將兩個ASCIIArt圖形橫向或縱向結合的操作符。選用適當優先順序的操作符命名。縱向結合的例項
/_/\ —–
( ’ ’ ) / Hello \
( - ) < Scala |
| | | \ Coder /
(|) —–

class ASCIIArt(str:String){
      var markstr:ArrayBuffer[ArrayBuffer[String]]=new ArrayBuffer[ArrayBuffer[String]]();
      if(str!=null){
        str.split("[\r\n]+").foreach { line => var a=new ArrayBuffer[String]();a+=line;markstr+=a; }
      }
      override def toString()={
        var s="";
        markstr.foreach { s+=_.mkString+"\n"; }
        s;
      }
      def +(other:ASCIIArt)={
        var Str="";
        var j=0;
        for(i<- 0 until this.markstr.length){
          if(i<=other.markstr.length){
            Str=Str+markstr(i).mkString+other.markstr(i).mkString+"\n";
          }else{
            Str=Str+markstr(i).mkString+"\n";
          }
          j=j+1;
        }
        if(j<other.markstr.length){
          for(i<- j until other.markstr.length){
                Str=Str+other.markstr(i).mkString+"\n";
          }
        }
        new ASCIIArt(Str);
      }

  }

7.實現一個BigSequence類,將64個bit的序列打包在一個Long值中。提供apply和update操作來獲取和設定某個具體的bit

class BigSequence{
     var SeqNum=new Array[Int](64);
     for(i<- (0 until SeqNum.length)){
       SeqNum(i)= -1;
     }
     def pack():Long={
        SeqNum.filter(_ >= 0).mkString.toLong
     }




  }
  object BigSequence{
    def apply(num:Int,input:BigSequence):Int={
        input.SeqNum(num);
    }
    def apply(num:Int)={
      val b = new BigSequence
      var i = 0
      num.toString.foreach{
      n=>
      b.SeqNum(i) = n.getNumericValue
      i+=1
    }
    b
    }
     def update(num:Int,input:BigSequence,value:Int)={
       input.SeqNum(num)=value;
     }
  }

8.提供一個Matrix類—你可以選擇需要的是一個2*2的矩陣,任意大小的正方形矩陣,或m*n的矩陣。支援+和操作。操作應同樣適用於單值,例如mat*2。單個元素可以通過mat(row,col)得到

class Matrix(row:Int=2,col:Int=2,content:Array[Int]){
     private val rowIndex=row;
     private val colIndex=col;
     private val co:Array[Int]=if(content.length<row*col) {
        val s=for(i <- (0 until row*col)) yield {
          if(i<content.length){ 
            content(i) 
          }else 0
        }
        s.toArray;
     }else{
       val s = for(i <- (0 until row*col)) yield {
         content(i)
       }
       s.toArray
     }
     def +(other:Matrix):Matrix={
       if((this.rowIndex==other.rowIndex)&&(this.colIndex == other.colIndex)){
         val s=for(i<-(0 until this.co.length)) yield {
            this.co(i)+other.co(i);
         }
         new Matrix(rowIndex,colIndex,s.toArray);
       }else null;

     }
     def -(other:Matrix):Matrix={
       if((this.rowIndex==other.rowIndex)&&(this.colIndex == other.colIndex)){
         val s=for(i<-(0 until this.co.length)) yield {
            this.co(i)-other.co(i);
         }
         new Matrix(rowIndex,colIndex,s.toArray);
       }else null;
     }
     def *(other:Matrix):Matrix={
        if(this.colIndex==other.rowIndex){
          val s:Array[Int]=new Array[Int](this.rowIndex*other.colIndex);
          for(i<-(0 until this.rowIndex )){
             for(j<- (0 until other.colIndex)){
                var sum=0;
                for(m<-( 0 until this.colIndex)){
                  val e=this.co(i*this.colIndex+m)
                  val d=other.co(m*other.colIndex+j)
                  sum=sum+e*d;
                }
                s(i*this.rowIndex+j)=sum;
             }
          }
          new Matrix(this.rowIndex,other.colIndex,s)
        }else null
     }
     def *(mat:Int):Matrix={
       val s=for(i<- (0 until this.co.length)) yield{
         this.co(i)*mat;
       }
       new Matrix(this.rowIndex,this.colIndex,s.toArray);
     }
     def show()={
       for(i<- (0 until this.co.length)){
         print(co(i)+",");
       }
     }

  }
  object Matrix{
     def apply(row:Int=2,col:Int=2,content:Array[Int])={
       new Matrix(row,col,content:Array[Int]);
     }
  }

9.為RichFile類定義unapply操作,提取檔案路徑,名稱和副檔名。舉例來說,檔案/home/cay/readme.txt的路徑為/home/cay,名稱為readme,副檔名為txt

  def unapply(path:String)={
    val pa=path.split("/");
    val index=pa(pa.length-1).indexOf(".")
    Some((pa(pa.length-1).substring(0, index),pa(pa.length-1).substring(index+1,pa(pa.length-1).length())));

  }

10.為RichFile類定義一個unapplySeq,提取所有路徑段。舉例來說,對於/home/cay/readme.txt,你應該產出三個路徑段的序列:home,cay和readme.txt

 def unapplyseq(path:String):Option[Seq[String]]={
    Some(path.split("/"));

  }

9和10中unapply的使用方法,這裡給個例子

 val Fraction(r)=f;
 println(r);
 def unapply(input:Fraction):Option[(Int,Int)]={
        if(input.den==0) None else Some((input.num,input.den));
     }