scala学习笔记1-泛型、界定、形变、this.type、复合类型、抽象类型

https://blog.csdn.net/sucabit/article/details/50001667 

一、Scala中的泛型

class Triple[F: ClassTag, S : ClassTag, T : ClassTag](val f : F, val s : S, val t :T)  <span style="font-family: Arial, Helvetica, sans-serif;">//其中,ClassTag在scala.reflect.ClassTag中,并且ClassTag是隐式的,可省略;</span>
val t1 = new Triple("hadoop", "spark", "bigdata");
val t2 = new Triple[String, Int, Double]("bigdata", 1, 1.0);


 

二、Scala中Bounds(界定)

    一般的Bounds

    <: 使得T必须是Comparable[T]的子类,这T类型的a,b才有compareTo方法。

 

class Pair[T <: Comparable[T]](val a : T, val b : T)
if(a.compareTo(b)> 0) a else b

 

    View Bounds(视图界定)

 

class Pair2 [T <% Comparable[T]](val a : T, val b :T)
<% 使得T不是Comparable[T]的子类型,隐式转为它的子类。比如传入的是Int类型,Int类型没有实现Comparable[T]。故先要将Int隐式转为RichInt,此时RichInt是Comparable[T]的子类
class Pair3 [T <% Ordered[T]](val a : T, val b : T)
转为Ordered[T],可以将对象以a > b 的形式进行比较。If(a>b) a else b,其实>是a的方法

 

 

    Context Bounds

 

class Pair_Ordering [T : Ordering : ClassTag](val a : T, val b : T) {
     def bigger(implicit ordered : Ordering[T]) ={
         if(ordered.compare(a, b) > 0) a else b
      }
}
T :Ordering表示存在一个隐式值为Ordering[T]

 

 

     Manifest、classManifest、ClassTag、TypeTag

      利用Manifest可以创建泛型数组。Manifest中存储了T的实际类型的信息,在实际运行中作为参数运行在上下文环境中。其中T:Manifest和上文的T:Ordering都属于Context Bounds的用法

 

def arrayMake[T : Manifest](a : T, b : T) = {
    val array = new Array[T](2);
    array(0) = a;
    array(1) = b;
    array;
}

 

 

         后来,Manifest和classManifest分别被TypeTag和ClassTag所取代。ClassType的限定要弱于TypeTag。ClassType提供了运行时的类型信息,而TypeTag提供了所有的静态类型信息。而实际中,ClassType提供的运行时类型信息已经足够使用,因此在spark等中使用广泛。

           def arrayMake2[T : ClassTag](elems : T*) = Array[T](elems : _*)

            ,这里可以看到T:ClassTag,自动隐式转为ClassTag[T]

            arrayMake2(1,2).foreach(println)

           主要是在运行时指定在编译时无法确定的比较高级别的类别的信息,不包括static级别的type信息。

    多重界定

          T <:A with B 表示T是A或B的子类。

          T : A: B 是上下文界定。表示必须同时存在A[T]和B[T]的隐式值。

          T <% A <% B 是视图界定,表示T可以隐式转为A且B。

          T>: A <: B 表示A是T的下界,B是T的上界。并且,下界A必须写在上界B的前面,同时A一定是B的子类。

三、 Scala的类型约束

     A =:=B 表示A类型等同B类型

     A<:< B 表示A类型是B类的子类型

四、 Scala中的Variance

    Variance称为形变 T

       协变 +T

       逆变 –T

       class  Person[+T](first : T, second : T) 则后面的first和second的类型必须是T的父类。-T的话,表示first和second的类型必须是T的子类。

五、 Scala中的链式调用

     任何的类对象都有type属性:this.type

 

class Animal {
  def breathe() : this.type = {
      //TODO
      this
  }
}
    
class Dog extends Animal {
 def eat() : this.type = {
    //TODO
    this
  }
}
Val dog = new Dog; dog.breathe().eat();

 

 

六、 Scala中的路径依赖

    内部类享有外部类的实例,可以访问外面类中的私有成员;而外部类不可以访问内部类中的私有成员。

    Scala中内部类必须依赖于外部类的实例。外部类实例不同,则内部类也不同,依赖于外部类,称为路径依赖,不同路径下的内部类,类型不同。

 

class Outter {
   private[this] val x = 1
     
   class Inner {
      private[this] val y = x + 1
    }
}
 
object PathDependencies extends App {
  val out1 = new Outter
  val out2 = new Outter
 
  //out1.Inner和out2.Inner在不同路径下,类型不同
  val inner1 : out1.Inner = new out1.Inner
  val inner2 : out2.Inner = new out2.Inner
 
  //类型投影,out1.Inner,out2.Inner是Outter#Inner的子类
  val inner3 : Outter#Inner = new out1.Inner
  val inner4 : Outter#Inner = new out2.Inner
}

 

 

七、 Scala中的结构体类型

 

//传入实现get方法的匿名类实例
init(new {def get() = println("geted")})
       
//申明一个含有get方法的类型,类型于c语言中的结构体类型
type X = {//不需要像java那样,通过接口和实现接口来限制
   def get() : Unit
}
def init1(res : X) = {
   res.get
}
init1(new {def get() = println("geted again")})
object A {def get() = println("geted In A")}
init1(A)

 

 

八、 Scala中的复合类型

 

trait A //接口A
trait B //接口B
class C extends A with B {//继承A,B,实现get的C
   def get() = println("hello compoundtype!")
}
   
object CompoundType {
    //复合类型,该类型表示既是A又是B,同时还要实现get方法
    type CompoundType = A with B {def get():Unit}
 
    def init(x : CompoundType)  = {
       x.get()
    }

    def main(args: Array[String]): Unit = {
      init(new C)
    }
}

 

 

九、 Scala中的InfixType

 

object InfixType {
   def main(args: Array[String]): Unit = {
       //右结合的表达式
      "Spark" >>: "Hadoop">>: Log
       
       val list = List()
       val newList = 1 :: 2 :: list
       println(newList)
       
       class Infix_Type[A, B]
       val it : Infix_Type[Int, String] =null
       val it1 : Int Infix_Type String =null
   
       val cons =Constant("1", "2")
       cons match {
         case "1" Constant "2"=> {
          println("spark!")
         } 
       }
   }
}
case class Constant(first : String, second : String)
 object Log {
   def >>: (data : String) : Log.type = { // >>: 这是方法名
     println(data);
     Log
  }
}

 

 

 

 

十、Self Types

      自类型, 相当于对当前实例关键this起一个别名。用法如下://有点类似于javascript中的var self = this; 的用法

 

Class Outter {
   self =>
   val i
   Class Inner {
      def foo(){ println(self.i) }
   }
}

 

      主要用途在对this的一种限定,必须要混入另一个类型。用法如下:

 

trait S1
class S2 {
     this:S1=>
}
val s = new S2 with S1  //实例化S2的时候需要with S1
class S3 extends S2 with S1  //extends S2的时候需要 with S1

 

十一、 Scala中的依赖注入

      通过self type的用法,实现依赖组件的注入

 

object DependenceInjection extends App {
   T.authorize()
}
trait Logger{
   def log(msg:String)
}
class Auth{
   auth : Logger => //关键点
   val key = "hello di"
   def authorize() = {
     log(key)
      //TODO
   }
}

//T对象继承Auth则必须with Logger实现log方法
object T extends Auth with Logger {
   override def log(msg:String) = {
     println(msg)
   }
}

 

十二、 Scala中的抽象类型AbstractType

     抽象类通过type声明类型,但不指定具体的类型

     在子类中指定相关类型,和实现抽象类中的方法

 

trait Reader {
     type input <: java.io.Serializable //input 必须是Serializable的子类
     type results
     def read(str : input) : results
}              

class FileReader extends Reader {
    type input = String
    type results = BufferedSource
    override def read(str : input):results = {
        Source.fromFile(str)
    }
}
在使用Python来安装geopandas包,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多数用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造文件名 new_filename = 'geopandas_' + filename # 构造文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值