Scala的集合操作之可变数组和不可变数组,可变List集合与不可变List集合,可变Set与不可变Set操作,可变和不可变Map集合和元组操作

Scala的集合操作之,可变数组和不可变数组,可变List集合与不可变List集合

不可变数组

/*
traversable/ˈtrævəsəbl/adj.能越过的;可否认的*/
object Test01_ImmutableArray {def main(args: Array[String]): Unit = {// 1. 创建数组val arr: Array[Int] = new Array[Int](5)// 另一种创建方式/*Array.apply(12, 37, 42, 58, 97)通过Array伴生对象的apply方法获取一个数组对象,apply方法可以省略。等价于Array(12, 37, 42, 58, 97)*/val arr2 = Array(12, 37, 42, 58, 97)println(arr)// 2. 访问元素println(arr(0))println(arr(1))println(arr(4))
//    println(arr(5))arr(0) = 12arr(4) = 57println(arr(0))println(arr(1))println(arr(4))println("========================")// 3. 数组的遍历// 1) 普通for循环
//    for (i <- 0 to arr.length-1) println(arr(i))for (i <- 0 until arr.length){println(arr(i))}/*源码注释:Produces the range of all indices of this sequence.@return  a `Range` value from `0` to one less than the length of this $coll.indices方法实际上还是返回Range伴生对象的until方法def indices: Range = 0 until length*/for (i <- arr.indices) println(arr(i))println("---------------------")// 2) 直接遍历所有元素,增强for循环for (elem <- arr2) println(elem)println("---------------------")// 3) 迭代器val iter = arr2.iteratorwhile (iter.hasNext)println(iter.next())println("---------------------")// 4) 调用foreach方法arr2.foreach( (elem: Int) => println(elem) )// 下面这个foreach遍历跟上面的等价arr.foreach( println )println(arr2.mkString("--"))println("========================")// 4. 添加元素val newArr = arr2.:+(73)println(arr2.mkString("--"))println(newArr.mkString("--"))val newArr2 = newArr.+:(30)println(newArr2.mkString("--"))val newArr3 = newArr2 :+ 15val newArr4 = 19 +: 29 +: newArr3 :+ 26 :+ 73println(newArr4.mkString(", "))}
}

可变数组ArrayBuffer

/*** with: 和...在一起,具有,支持的含义* 一个类继承一个特质用extends,多个特质用,extends ..with..* class 类名 extends 特质 1 with 特质 2 with 特质 3...*/
object Test02_ArrayBuffer {def main(args: Array[String]): Unit = {// 1. 创建可变数组val arr1: ArrayBuffer[Int] = new ArrayBuffer[Int]()val arr2 = ArrayBuffer(23, 57, 92)println(arr1)println(arr2)// 2. 访问元素
//    println(arr1(0))     // errorprintln(arr2(1))arr2(1) = 39println(arr2(1))println("======================")// 3. 添加元素,:+操作会返回一个新的数组对象,+=操作返回的是原数组自身对象val newArr1 = arr1 :+ 15println(arr1)println(newArr1)println(arr1 == newArr1)//可变数组推荐使用+=操作val newArr2 = arr1 += 19println(arr1)println(newArr2)println(arr1 == newArr2)newArr2 += 13println(arr1)77 +=: arr1println(arr1)println(newArr2)println("==============================")/*append(元素)向数组末尾添加一个元素prepend(元素)向数组头部添加一个元素insert(元素1,元素2)向数组插入多个元素insertAll(2, newArr)向数组2索引位置开始插入一个新的数组prependAll(newArr)向数组头部插入一个新的数组*/arr1.append(36)arr1.prepend(11, 76)arr1.insert(1, 13, 59)println(arr1)arr1.insertAll(2, newArr1)arr1.prependAll(newArr2)println("************************")println("arr1: ==> " + arr1)/*** 删除操作:* remove(n: Int, count: Int)方法,从数组n索引位置开始删除count个元素* remove(n: Int)删除数组n索引位置的数据*/// 4. 删除元素arr1.remove(3)println(arr1)arr1.remove(0, 10)println(arr1)//调用 -=方法删除某个元素arr1 -= 13println(arr1)// 5. 可变数组转换为不可变数组val arr: ArrayBuffer[Int] = ArrayBuffer(23, 56, 98)val newArr: Array[Int] = arr.toArrayprintln(newArr.mkString(", "))println(arr)// 6. 不可变数组转换为可变数组val buffer: mutable.Buffer[Int] = newArr.toBufferprintln(buffer)println(newArr)}
}

多维数组

object Test03_MulArray {def main(args: Array[String]): Unit = {// 1. 创建二维数组val array: Array[Array[Int]] = Array.ofDim[Int](2, 3)// 2. 访问元素array(0)(2) = 19array(1)(0) = 25println(array.mkString(", "))for (i <- 0 until array.length; j <- 0 until array(i).length){println(array(i)(j))}for (i <- array.indices; j <- array(i).indices){print(array(i)(j) + "\t")if (j == array(i).length - 1) println()}array.foreach(line => line.foreach(println))array.foreach(_.foreach(println))}
}

不可变List集合

/** List底层源码,Scala在List包对象中对List类型进行了重定义:type List[+A] = scala.collection.immutable.List[A]* 我们可以看到,这里的List实际上就是来自不可变集合包下的List.*  List是一个抽象类,sealed abstract class List[+A];无法直接New对象,它继承了AbstractSeq特质,具有LinearSeq[A]等特质*  与List抽象类对应的有一个同名的伴生对象List,我们可以调用伴生对象的apply方法创建List[T] 集合*/
object Test04_List {def main(args: Array[String]): Unit = {// 1. 创建一个List,不可变的List//val list1 = List.apply(23, 65, 87),因为apply方法调用可以简化,直接写成List(元素1,元素2,...)val list1 = List(23, 65, 87)println(list1)// 2. 访问和遍历元素println(list1(1))
//   list没有索引list1.foreach(println)/*3. 添加元素+: 向list集合前面头部添加元素:+ 向list集合尾部添加元素*/val list2 = 10 +: list1val list3 = list1 :+ 23println("list1: "+list1)println("list2: "+list2)println("list3: "+list3)println("==================")/*** 双冒号的功能:*  ::是Lits集合自带的方法,用于为集合添加一个元素,直接添加到集合的头部*  例如:list2.::(51),在list2集合前面添加一个51的元素*  Nil.::(13)也可以为一个空的list集合添加一个元素*/val list4 = list2.::(51)println("list4: "+list4)val list5 = Nil.::(13)println("list5: "+list5)val list6 = 73 :: 32 :: Nil// Nil空list集合对象,可以链式调用双冒号方法从右向左依次去添加元素val list7 = 17 :: 28 :: 59 :: 16 :: Nilprintln("list7: "+ list7)// 4. 合并列表val list8 = list6 :: list7println("list8: "+list8)/*** 三冒号和++ 操作:* ::: 与++ 都能实现将一个list集合所有元素加入另外一个list集合中*/val list9 = list6 ::: list7println("list9: "+ list9)val list10 = list6 ++ list7println("list10: "+ list10)}
}

可变List集合ListBuffer操作

object Test05_ListBuffer {def main(args: Array[String]): Unit = {// 1. 创建可变列表val list1: ListBuffer[Int] = new ListBuffer[Int]()val list2 = ListBuffer(12, 53, 75)println("list1 ==> " + list1)println("list2 ==> " + list2)println("==============")// 2. 添加元素list1.append(15, 62)list2.prepend(20)list1.insert(1, 19, 22)println("list1 ==> " + list1 )println("list2 ==> " + list2)println("==============")/***  +=:带冒号的操作是从右向左,向头部添加元素*  += 不带冒号的操作方法是默认加到list集合后边**/31 +=: 96 +=: list1 += 25 += 11println("list1 ==> " + list1)println("==============")// 3. 合并list,++操作方法是克隆原来的集合,在复制的集合上进行操作。合并后返回一个新的集合val list3 = list1 ++ list2println("list1 ==> " + list1)println("list2 ==> " + list2)println("==============")// ++=会直接覆盖原来的集合list1 ++=: list2println("list1 ==> " + list1)println("list2 ==> " + list2)println("==============")// 4. 修改元素,把索引位置为3的元素修改为30list2(3) = 30 //它底层调用了update方法list2.update(0, 89)println("list2 ==> " + list2)// 5. 删除元素,指定某个索引位置的元素,也可以使用-=操作方法list2.remove(2)list2 -= 25println("list2 ==> " + list2)}
}

不可变Set集合操作

object Test06_ImmutableSet {def main(args: Array[String]): Unit = {// 1. 创建set,使用Set的伴生对象创建Set集合,set集合无序,因此会去重val set1 = Set(13, 23, 53, 12, 13, 23, 78)println(set1)println("==================")// 2. 添加元素//val set2 = set1.+(129)跟下面的等价val set2 = set1 + 129println(set1)println(set2)println("==================")// 3. 合并两个set集合,使用++操作方法,会返回一个新的set的集合val set3 = Set(19, 13, 23, 53, 67, 99)val set4 = set2 ++ set3println(set2)println(set3)println(set4)// 4. 删除元素,使用-val set5 = set3 - 13println(set3)println(set5)}
}

可变Set集合mutable.Set操作

object Test07_MutableSet {def main(args: Array[String]): Unit = {// 1. 创建setval set1: mutable.Set[Int] = mutable.Set(13, 23, 53, 12, 13, 23, 78)println("set1 => " +set1)println("==================")// 2. 添加元素val set2 = set1 + 11println("set1 => " + set1)println("set2 => " + set2)set1 += 11println("set1 => " + set1)val flag1 = set1.add(10)println("flag1 => " + flag1)println("set1 => " + set1)val flag2 = set1.add(10)println("flag2 => " + flag2)println("set1 => " + set1)println("==================")// 3. 删除元素set1 -= 11println(set1)val flag3 = set1.remove(10)println("flag3 => " + flag3)println("set1 => " + set1)val flag4 = set1.remove(10)println("flag4 => " + flag4)println("set1 => " + set1)println("==================")// 4. 合并两个Setval set3 = mutable.Set(11,22,33)println("set1: " + set1 )println("set3 => " + set3 )println("******************")// 合并set1集合与set3集合,返回合并后的新的集合val set4= set1 ++ set3// println("set4: " + set4 )//set3 ++= set1就会把set1集合的元素合并到set3里面set3 ++= set1 //set3调用 ++=方法, 谁调用谁改变println("set1: " + set1)println("set3 => "+ set3)}
}

Scala集合操作之可变Map 集合和不可变Map集合,元组数据操作

不可变Map集合

object Test08_ImmutableMap {def main(args: Array[String]): Unit = {// 1. 创建mapval map1: Map[String, Int] = Map("a" -> 13, "b" -> 25, "hello" -> 3)println(map1)println(map1.getClass)println("==========================")// 2. 遍历元素map1.foreach(println)map1.foreach( (kv: (String, Int)) => println(kv) )println("============================")// 3. 取map中所有的key 或者 value// keys是包含所有key的Iterable[K]集合// 也可以获取所有map集合的所有key的keySet集合,然后遍历keySet集合获取所有key,在根据key获取value值for (key <- map1.keys){println(s"$key ---> ${map1.get(key)}")}// 4. 访问某一个key的valueprintln("a: " + map1.get("a").get)/***  map1.get("a")获取的是一个Option[+A] 类型,但Option是一个密封的抽象类,对应有两个实现:一个为None: 如果根据key获取不到值,返回的就是一个空集合对象,对应的就是 Nonecase object None extends Option[Nothing] {def isEmpty = truedef get = throw new NoSuchElementException("None.get")}另外一个为:Some: 如果根据key获得值了,返回的就是 Somefinal case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A] {def isEmpty = falsedef get = value@deprecated("Use .value instead.", "2.12.0") def x: A = value}* map1集合里面没有key为c的键值对,如果去获取value值就会报空指针异常* 为了避免报异常可以调用 getOrElse("c", 0)这个方法,含义是如果对应的键值对存在则返回,不存在默认返回0*/println("c: " + map1.get("c"))println("c: " + map1.getOrElse("c", 0))//map1.put() 不可变Map是不能往里面添加元素的println(map1("a"))}
}

可变Map操作

object Test09_MutableMap {def main(args: Array[String]): Unit = {// 1. 创建mapval map1: mutable.Map[String, Int] = mutable.Map("a" -> 13, "b" -> 25, "hello" -> 3)println(map1)println(map1.getClass)println("==========================")// 2. 添加元素map1.put("c", 5)map1.put("d", 9)println(map1)/** 使用符号添加数据,+=方法,底层调用的是update方法,*  ` def update(key: K, value: V) { this += ((key, value))     } `* += 后面跟了一个k-v键值对的二元组,因此可以使用这种方式添加元素*/map1 += (("e", 7)) //("e", 7)这个一个key-vale的二元组println(map1)println("===========================")// 3. 删除元素println(map1("c"))map1.remove("c")println(map1.getOrElse("c", 0))map1 -= "d"println(map1)println("====================")// 4. 修改元素map1.update("c", 5)map1.update("e", 10)println(map1)println("====================")// 5. 合并两个Mapval map2: Map[String, Int] = Map("aaa" -> 11, "b" -> 29, "hello" -> 5)// 符号操作为 ++=//   把map2中的所有键值对元素,添加到map1中map1 ++= map2println(map1)println(map2)println("---------------------------")val map3: Map[String, Int] = map2 ++ map1println(map1)println(map2)println(map3)}
}

元组操作

object Test10_Tuple {def main(args: Array[String]): Unit = {// 1. 创建元组val tuple: (String, Int, Char, Boolean) = ("hello", 100, 'a', true)println(tuple)// 2. 访问数据println(tuple._1)println(tuple._2)println(tuple._3)println(tuple._4)println(tuple.productElement(1))println("=========================")// 3. 遍历元组数据for (elem <- tuple.productIterator)println(elem)// 4. 嵌套元组val mulTuple = (12, 0.3, "hello", (23, "scala"), 29)println(mulTuple._4._2)}
}

for推导式和yield关键字

for推导式的用法

Scala中的for推导式是一种用于对集合进行迭代和转换的强大工具。它提供了一种简洁的语法来处理集合中的元素,并生成新的集合或执行特定的操作。

for推导式的基本语法如下:

for (pattern <- collection) {// 循环体
}

其中,pattern是一个模式,用于解构集合中的元素,collection是要遍历的集合。

以下是几种常见的for推导式的用法:

  1. 遍历集合并执行操作:
val numbers = List(1, 2, 3, 4, 5)
for (num <- numbers) {println(num)
}

上述示例中,for推导式遍历numbers列表中的每个元素,并将其打印出来。

  1. 过滤并转换集合元素:
val numbers = List(1, 2, 3, 4, 5)
val evenSquares = for (num <- numbers if num % 2 == 0) yield num * num
println(evenSquares)

上述示例中,for推导式通过添加if条件来过滤出偶数,然后将符合条件的偶数平方存储在evenSquares列表中。

  1. 多个集合的交叉操作:
val colors = List("red", "green", "blue")
val sizes = List("small", "medium", "large")
val combinations = for {color <- colorssize <- sizes
} yield (color, size)
println(combinations)

上述示例中,for推导式嵌套遍历colorssizes列表,并生成颜色和尺寸的所有可能组合。

除了基本语法之外,for推导式还可以使用模式匹配、嵌套条件、变量绑定等更高级的特性。您可以根据具体的需求来灵活使用和组合这些特性,以实现更复杂的逻辑。

需要注意的是,for推导式在编译时会被转换为其他高阶函数(如mapfilterflatMap等),因此它具有与使用高阶函数相似的性能特性和灵活性。

yield的使用

在Scala中,yield是一个关键字,用于生成集合或其他类型的值。它通常用于for循环中,以遍历集合元素并执行某些操作。以下是yield关键字的主要用法:

  1. 在for循环中生成新的集合
val numbers = List(1, 2, 3, 4, 5)
val squares = for (number <- numbers) yield number * number
println(squares) // 输出: List(1, 4, 9, 16, 25)

上述示例中,yield关键字用于在for循环中生成新的集合squares,这个新的集合的元素是通过对原始集合numbers的每个元素进行平方运算得到的。

  1. 与模式匹配一起使用
case class Person(name: String, age: Int)val people = List(Person("Alice", 25), Person("Bob", 30), Person("Charlie", 35))
val names = for (Person(name, _) <- people) yield name
println(names) // 输出: List(Alice, Bob, Charlie)

上述示例中,yield关键字用于提取people列表中每个Person对象的name属性,并生成一个新的列表names

  1. 用于表达式求值
val result = (for (i <- 1 to 10) yield i * i).sum
println(result) // 输出: 385

在上述示例中,yield关键字用于生成一个包含1到10的数值的集合,并对每个元素求平方。随后,调用sum方法对所有元素进行求和,并返回结果。

需要注意的是,在Scala中,yield关键字只会将新的集合或值返回给程序的其他部分,它不会修改原始的集合或任何其他的状态。此外,yield关键字只能用于带有for循环的语句中,且只有仅包含一个表达式的for循环才能使用yield生成结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/67649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频监控/视频汇聚/视频云存储EasyCVR平台HLS流集成在小程序无法播放问题排查

安防视频/视频云存储/视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频…

字节前端实习的两道算法题,看看强度如何

最长严格递增子序列 题目描述 给你一个整数数组nums&#xff0c;找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7…

flink实现kafka、doris精准一次说明

前言说明:本文档只讨论数据源为kafka的情况实现kafka和doris的精准一次写入 flink的kafka连接器已经实现了自动提交偏移量到kafka,当flink中的数据写入成功后,flink会将这批次数据的offset提交到kafka,程序重启时,kafka中记录了当前groupId消费的offset位置,开始消费时将…

文件系统与inode编号

文件描述符fd 0&1&2 Linux 进程默认情况会有3个缺省打开的文件描述符&#xff0c;分别是标准输入0&#xff0c; 标准输出1&#xff0c; 标准错误2. 0,1,2对应的物理设备一般是&#xff1a;键盘&#xff0c;显示器&#xff0c;显示器 所以输入输出还可以采用如下方式 …

中国非晶纳米晶行业市场预测与投资战略报告(2023版)

内容简介&#xff1a; 由于性能优异&#xff0c;非晶材料从20世纪80年代开始成为中国外科学界研究重点&#xff0c;目前美、日、德已经具备完善的生产规模&#xff0c;大量的非晶合金产品逐渐取代硅钢、铁氧体等。 2021年之前&#xff0c;中国铁基非晶带材企业有12家&#xf…

AVR128单片机 自动售水机

一、系统方案 1、设计使用两个按键分别为S1和S2及一个发光二极管LED。S1为出水控制按键&#xff0c;当S1按下&#xff0c;表示售水机持续出水&#xff0c;继电器&#xff08;库元件relay&#xff09;接通&#xff0c;指示灯LED亮。S2为停水控制键&#xff0c;当S2按下&#xff…

CSS面试题

CSS面试题 1.说说flexbox&#xff08;弹性盒布局模型&#xff09;,以及适用场景&#xff1f;flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content 2.让Chrome支持小于12px 的文字方式有哪些&#xff1f;区别&#xff1f;3.css选择器有哪些? 优先级? 哪…

OSCS 安全周报第 58 期:VMware Aria Operations SSH 身份验证绕过漏洞 (CVE-2023-34039)

​ 本周安全态势综述 OSCS 社区共收录安全漏洞 3 个&#xff0c;公开漏洞值得关注的是 VMware Aria Operations SSH 身份验证绕过漏洞( CVE-2023-34039 )、Apache Airflow Spark Provider 反序列化漏洞( CVE-2023-40195 )。 针对 NPM 仓库&#xff0c;共监测到 324 个不同版本…

9月3日,每日信息差

第一、中国中铁与广州市城中村改造做地主体签署战略合作框架协议。根据协议&#xff0c;双方将积极响应广州市统筹做地推进高质量发展工作精神&#xff0c;充分发挥双方优势资源&#xff0c;共同加大在物业复建安置、基础设施建设、综合开发投资、城中村改造&#xff08;微改造…

volatile 关键字 与 CPU cache line 的效率问题

分析&回答 Cache Line可以简单的理解为CPU Cache中的最小缓存单位。目前主流的CPU Cache的Cache Line大小都是64Bytes。假设我们有一个512字节的一级缓存&#xff0c;那么按照64B的缓存单位大小来算&#xff0c;这个一级缓存所能存放的缓存个数就是512/64 8个。具体参见下…

【跟小嘉学 Rust 编程】二十三、Cargo 使用指南

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

百度低质量站点怎么办?解决百度低质量站点的方法和工具

百度低质量站点怎么恢复&#xff1f;这是许多网站主和运营人员在SEO优化过程中经常面临的一个问题。百度作为中国最大的搜索引擎&#xff0c;对于网站收录和排名具有至关重要的影响。然而&#xff0c;由于各种原因&#xff0c;有些网站可能面临被百度降权或收录减少的情况。那么…

go、Java、python三门语言的优缺点和各自擅长做什么

Go、Java和Python都是目前非常流行和实用的编程语言&#xff0c;它们各有各的特点和适用场景&#xff0c;没有绝对的优劣之分&#xff0c;只有适合不适合的问题。下面我就简单地对比一下它们的主要特征和应用领域。 Go语言是一种简洁、高效、并发的编程语言&#xff0c;它可以…

vue3.3 ~

defineModel 原本&#xff1a; // 1 defineProps({modelValue: {type: Number,required: true,default: 0} })defineProps([modelValue]) // 2 const emit defineEmits([update:modelValue])现在&#xff1a; const value defineModel<number>({ default: 0 })defin…

Medium: Where to Define Qualified users in A/B testing?

1. Common AB Testing Setup Issue (Framework) 局限性: unqualified users will also be considered and mess up experimentation results.

SeaTunnel扩展Transform插件,自定义转换插件

代码结构 在seatunnel-transforms-v2中新建数据包名&#xff0c;新建XXXTransform&#xff0c;XXXTransformConfig&#xff0c;XXXTransformFactory三个类 自定义转换插件功能说明 这是个适配KafkaSource的转换插件&#xff0c;接收到的原文格式为&#xff1a; {"path&…

华为OD机试 - 找出经过特定点的路径长度 - 深度优先搜索(Java 2022 Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

【记录】USSOCOM Urban3D 数据集读取与处理

Urban3D数据集内容简介 Urban3D数据集图像为正摄RGB影像&#xff0c;分辨率为50cm。 从SpaceNet上使用aws下载数据&#xff0c;文件夹结构为&#xff1a; |- 01-Provisional_Train|- GT|- GT中包含GTC&#xff0c;GTI&#xff0c;GTL.tif文件&#xff0c;GTL为ground truth b…

合并两个有序链表(每日一题)

“路虽远&#xff0c;行则将至” ❤️主页&#xff1a;小赛毛 ☕今日份刷题&#xff1a;合并两个有序链表 题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例1&#xff1a; 输入&#xff1a;l1 …

web pdf 拖拽签章

web pdf 拖拽签章 主要通过火狐的pdfjs 来实现 1. 下载js 并编译 地址 https://mozilla.github.io/pdf.js/ 按照官网当下下载并编译就得到了js 2.其实也没有什么好讲的&#xff0c;都是用的js中的方法&#xff0c;官网中都有 按照步骤就能生成一个document元素&#xff0c;然…