#generic #linked-list #bidirectional #typed-list #static-dispatch

dynamic-list

一个功能强大且高效的动态列表实现,具有多种数据结构,能够存储任何类型的数据!

3 个版本 (破坏性更新)

0.3.0 2023 年 12 月 7 日
0.2.0 2023 年 11 月 30 日
0.1.0 2023 年 11 月 27 日

#1398数据结构

MIT/Apache

21KB
474 代码行

动态列表

一个功能强大且高效的动态列表实现,具有多种数据结构。它设计用于存储任何类型的数据,而不需要额外的成本,因此是各种应用的理想选择。其主要优点之一是避免了动态分发的额外成本。

目前提供两种实现

  • 双链表:一种单向链表,能够高效地在两个方向上进行迭代。
  • 数组:一个固定大小的数组,其中所有元素都连续存储在堆栈中。

安装 🚀

将以下内容添加到您的 Cargo.toml

[dependencies]
dynamic-list = "0.3.0"

或者,如果您想使用主分支上的最新版本

[dependencies]
dynamic-list = { git = "https://github.com/ferranSanchezLlado/dynamic-list.git" }

用法 🛠️

DynamicList 交互的主要方式是通过实现一个允许它通过递归调用自身进行迭代、归约或累加的特制。

示例 1:获取特定元素

use dynamic_list::*;
use typenum::*;

// Chain access:
let array = array![1u8, "hello", true, "world"];
assert_eq!(array.forward().next().value(), &"hello");
assert_eq!(array.backward().value(), &"world");

// Index access:
let list = list![1u8, "hello", true, "world"];
assert_eq!(Index::<U1>::index(list.forward()), &"hello");
assert_eq!(Index::<U3>::index(list.forward()), &"world");

示例 2:我们将一个项目的列表连接成一个字符串

use dynamic_list::{list::Node, *};

// Iterator trait
trait Concat {
    fn concat(&self) -> String;
}
impl<V: ToString + Clone> Concat for Node<V> {
    fn concat(&self) -> String {
        self.value().to_string()
    }
}
impl<V: ToString + Clone, N: Concat> Concat for Node<V, N> {
    fn concat(&self) -> String {
        format!("{}{}", self.value().to_string(), self.next().concat())
    }
}

let list = list![1u8, "_hello", -3i32];
assert_eq!(list.forward().concat(), "1_hello-3");
assert_eq!(list.backward().concat(), "-3_hello1");

示例 3:我们想要计算列表中偶数的数量

use dynamic_list::{list::Node, *};

// Polymorphic trait
trait Even {
    fn even(&self) -> usize;
}
impl<T: Clone + TryInto<usize>> Even for T {
    fn even(&self) -> usize {
        (self.clone().try_into().unwrap_or(1) + 1) % 2
    }
}

// Iterator trait
trait NumberEven {
    fn evens(&self) -> usize;
}
impl<V: Even> NumberEven for Node<V> {
    fn evens(&self) -> usize {
        self.value().even()
    }
}
impl<V: Even + Clone, N: NumberEven> NumberEven for Node<V, N> {
    fn evens(&self) -> usize {
        self.value().even() + self.next().evens()
    }
}

let list = list![false, 1, 2u8, -3, 4isize];
assert_eq!(list.forward().evens(), 3);

限制 ⚠️

虽然 Dynamic List 提供了强大且灵活的解决方案,但了解以下限制是很重要的

  • 特制实现要求:为了充分发挥列表的功能,列表中的值必须实现所需的特制。尝试在未实现它们的类型上调用特制方法将导致编译错误,这些错误可能难以解析。然而,随着 Rust 中特制特化的预期引入,这种限制可能得到缓解,允许更灵活的特制实现。例如,可以定义所有类型(除非特别指明)的默认值。值得注意的是,在数组中实现特制目前更为复杂。
  • 堆分配:目前,列表中的元素是在堆上分配的。虽然这种方法可以避免在列表中克隆值的需求,但它引入了与堆分配相关的潜在问题。如果堆分配对您的用例是关键考虑因素,您可能希望探索允许单向分配的替代实现,这可能会减少对内存管理的影响。需要注意的是,此限制不适用于基于数组的实现,后者将元素连续存储在字节数组中(可以存储在栈上)。

许可证 📄

本项目可根据您的选择,在以下许可下发布:[MIT 许可证](https://github.com/ferransanchezllado/dynamic-list/blob/6082b159751f7a2fcd494389257ca237e4cbf59d/MIT-LICENSE) 或 [Apache 许可证 2.0](https://github.com/ferransanchezllado/dynamic-list/blob/6082b159751f7a2fcd494389257ca237e4cbf59d/APACHE-LICENSE)。

依赖项

~155KB