- 作者:老汪软件技巧
- 发表时间:2024-08-20 00:04
- 浏览量:
Collection类型
仓颉中的集合类型包括Array、ArrayList、HashSet、HashMap
他们都是泛型的,可以支持任意类型他们都是引用类型。即赋值的时候相当于只是多了一个指针指向原数据Array 初始化之后,长度不可变,不能增删元素。其他三种可以增删元素
package cj_exercise.study
import std.collection.{ArrayList, HashSet, HashMap}
// 一个迭代器,内部维护迭代的次数,保存需要迭代的数据
class MyIteratorClass <: Iterator {
var index: Int = 0
private let dataList: Array
init(dataList: Array) {
this.dataList = dataList
}
public func next(): Option {
let v = dataList.get(index)
index += 1
return v
}
}
// 自定义可迭代的类
class MyIterableClass <: Iterable {
let list: Array
let name: String = 'MyIterableClass'
init(list: Array) {
this.list = list
}
// 需要返回一个迭代器用来迭代数据
// 这里迭代的数据是this.list
public func iterator(): Iterator {
MyIteratorClass(this.list)
}
}
public func collectionDemo() {
func arrayListDemo() {
// ArrayList 可变数组 适合于需要频繁增加和删除元素的场景
// 类型,ArrayList 在作为表达式使用时不会拷贝副本,同一个 ArrayList 实例的所有引用都会共享同样的数据。
// 初始化一个只能存放String类型的数组
let array0 = ArrayList()
// 虽然array0是使用let修饰,但是由于ArrayList本身是可变的,所以可以调用append方法添加元素
// 这里let的作用只是保证array0不能被重新赋值,但是修改array0里面的数据还是可以的
// array0 = ArrayList
array0.append('hi')
// 初始化一个100个容量的数组
let array1 = ArrayList(100)
// 使用现有Array创建一个数组
let array2 = ArrayList([1, 2, 3])
// 使用现有Collection创建一个数组
let array3 = ArrayList(array2)
// 创建一个容量为5,每个元素使用闭包构建的数组
let array4 = ArrayList(5, {i => i + 1})
// array4还可以使用尾随闭包实现
let array5 = ArrayList(5) {i => i + 1}
// 访问第一个元素
// 使用下标访问,超出范围时会崩溃
let e0 = array5[0]
// 使用get方法访问,返回一个Option,超出范围时返回Option.None
let e0_0 = array5.get(0)
if (let Some(e0) <- e0_0) {
println('第一个元素值为 ${e0}')
}
// 遍历数组
for (i in array5) {
println(i)
}
// 判断是否包含数据
array5.contains(5)
// 修改第一个元素的值
array5[0] = 10
array5.set(0, 20)
// 在尾部追加数据
array5.append(10)
array5.appendAll([1, 2, 3])
// 在某个index处插入数据
array5.insert(2, 2)
array5.insertAll(2, [2, 3, 10])
// 删除 第二个位置的 元素
array5.remove(2)
// 删除2到6位置的元素
array5.remove(2..=6)
// 把小于4的数据删除
array5.removeIf {data => data < 4}
}
func hasSetDemo() {
// HashSet 类型来构造只拥有不重复元素的 Collection
// T 必须是实现了 Hashable 和 Equatable 接口的类型
// 初始化一个只能存放String类型的set
let set0 = HashSet()
// 虽然set0是使用let修饰,但是由于HashSet本身是可变的,所以可以调用put方法添加元素
// 这里let的作用只是保证set0不能被重新赋值,但是修改set0里面的数据还是可以的
// set0 = HashSet()
set0.put('hi')
// 初始化一个100个容量的set
let set1 = HashSet(100)
// 使用现有Array创建一个set
let set2 = HashSet([1, 2, 3])
// 使用现有Collection创建一个set
let set3 = HashSet(set2)
// 创建一个容量为5,每个元素使用闭包构建的set
let set4 = HashSet(5, {i => i + 1})
// set4还可以使用尾随闭包实现
let set5 = HashSet(5) {i => i + 1}
// 遍历set
for (i in set5) {
println(i)
}
// 判断是否包含数据
set5.contains(2)
set5.containsAll([1, 2])
// 在尾部追加数据
set5.put(10)
set5.putAll([1, 2, 3])
// 删除 2 这个元素
set5.remove(2)
// 删除 1, 2 这两个元素
set5.removeAll([1, 2])
// 把小于4的数据删除
set5.removeIf {data => data < 4}
}
func hasMapDemo() {
// HashMap 类型来构造元素为键值对的 Collection
// K 必须是实现了 Hashable 和 Equatable 接口的类型
// V 表示 HashMap 的值类型,V 可以是任意类型
// 初始化一个只能存放String类型的map
let map0 = HashMap()
// 虽然map0是使用let修饰,但是由于HashMap本身是可变的,所以可以调用put方法添加元素
// 这里let的作用只是保证map0不能被重新赋值,但是修改map0里面的数据还是可以的
// map0 = HashMap()
map0.put('hi', 2)
// 初始化一个100个容量的map
let map1 = HashMap(100)
// 使用元素为元组类型的Array创建一个map
let map2 = HashMap([("a", 0), ("b", 1), ("c", 2)])
// 使用现有Collection创建一个map
let map3 = HashMap(map2)
// 创建一个容量为5,每个元素使用闭包构建的map
let map4 = HashMap(5, {i => ('key${i}', i)})
// map5还可以使用尾随闭包实现
let map5 = HashMap(5) {i => ('key${i}', i)}
// 遍历map
for ((k, v) in map5) {
println('key:${k} => value:${v}')
}
// 判断是否包含数据
map5.contains('key3')
map5.containsAll(['key1', 'key2'])
// 通过key获取数据
// 通过下标获取数据,对应key的值不存在的时候会崩溃
let v0 = map5['key2']
// 通过get获取数据,返回一个可选值
let v1 = map5.get('key2')
if (let Some(v) <- v1) {
println('v1的值是 ${v}')
}
// 添加修改数据
map5['key5'] = 5
map5.put('key5', 5)
map5.putAll([('key6', 6), ('key7', 7)])
// 只有map5里面没有key8时,才添加
map5.putIfAbsent('key8', 8)
// 删除 key为key4的 元素
map5.remove('key4')
// 删除 key为key1和key2 的元素
map5.removeAll(['key1', 'key2'])
// 删除key以a开头并且 value小于5 的元素
map5.removeIf() {k, v => k.startsWith('a') && v < 5}
}
func iterableDemo() {
// Range、Array、ArrayList 都是通过 Iterable 来支持 for-in 语法
let list = Array(80) {i => i}
let myCls = MyIterableClass(list)
for (i in myCls) {
println('for-in myCls ${i}')
}
let it = myCls.iterator()
while (let Some(i) <- it.next()) {
println('while-let myCls ${i}')
}
}
iterableDemo()
}
包
包是编译的最小单元,每个包可以单独输出 AST 文件、静态库文件、动态库文件等产物
模块是若干包的集合,是第三方开发者 发布的最小单元
包声明必须在源文件的非空非注释的首行
同一个包中的不同源文件的包声明必须保持一致。因为他们都处于同一文件夹下。而包名是.分割文件路径,只到最后的文件夹仓颉的包名需反映当前源文件相对于项目源码根目录 src 的路径,并将其中的路径分隔符替换为小数点
包内顶层声明的可见性有4种,访问级别排序为 public > protected > internal > private
internalprotectedpublic
不同顶层声明支持的访问修饰符和默认修饰符。内置类型都是public的
一个声明的访问修饰符 不得高于该声明中 用到的类型的访问修饰符 的级别
public 修饰的声明在其 初始化表达式或者函数体里面 可以使用本包可见的任意类型
public 修饰的顶层声明能使用匿名函数,或者任意顶层函数
导入语句在源文件中的位置必须在包声明之后,其他声明或定义之前
如果包的模块名或者包名被篡改,所有导入的地方都需要修改,否则在导入时会报错。
只允许导入当前文件可见的顶层声明或定义,导入不可见的声明或定义将会在导入处报错。
禁止通过 import 导入当前源文件所在包的声明或定义。
禁止包间的循环依赖导入,如果包之间存在循环依赖,编译器会报错
编译器会隐式的导入 core 包中所有的 public 修饰的声明
可以对导入进行重命名,既可以对导入的某个声明重命名,也可以对整个导入的包进行重命名