internal 教程

本页面向需要向 immut 或 mutable 添加矩阵运算并校验其输入的贡献者。下游代码无法导入 internal;它只能通过公开方法看到这些守卫。规则见 internal 设计。

快速上手

在仓库内部,在 moon.pkg 中导入该包,并把守卫引入作用域:

///|
// moon.pkg
import {
  "Luna-Flow/linear-algebra/internal",
}
///|
using @internal {trait HasShape, ensure_square, ensure_square_checked}

日常任务

添加一对受检/非受检方法

先用受检守卫校验,再调用非受检形式,这样受检/非受检定律就按构造成立:

///|
pub fn[T : Add + Zero] Matrix::anti_trace(
  self : Matrix[T],
) -> Result[T, LinearAlgebraError] {
  match ensure_square_checked(self) {
    Ok(_) => Ok(self.unchecked_anti_trace())
    Err(err) => Err(err)
  }
}

///|
pub fn[T : Add + Zero] Matrix::unchecked_anti_trace(self : Matrix[T]) -> T {
  ensure_square(self)
  let n = self.row
  let mut sum = Zero::zero()
  for i in 0..<n {
    sum = sum + self[i][n - 1 - i]
  }
  sum
}

访问时检查索引

选择行时使用 ensure_row_in_bounds,计算存储偏移之前使用 ensure_index_in_bounds;切勿只检查扁平偏移。

从外部观察结果

测试应当固定的是公开行为:

///|
test "the same guard in both packages" {
  let i = @immut.Matrix::from_2d_array([[1, 2, 3]])
  let m = @mutable.Matrix::from_2d_array([[1, 2, 3]])
  let ei = match i.trace() {
    Err(e) => e.message
    Ok(_) => ""
  }
  let em = match m.trace() {
    Err(e) => e.message
    Ok(_) => ""
  }
  inspect(ei == em, content="true")
}

进一步了解

仓库内新的类矩阵类型只需实现一次 HasShape,即可获得所有守卫。重构时请保持错误类型和消息不变:consistency 测试和下游用户都依赖它们。

常见陷阱

  • 在受检方法中调用会中止的守卫。 这样受检方法就会中止,而不是返回 Err。
  • 修改之后才检查。 在 mutable 中,请在第一次写入之前校验,使错误不会改变矩阵。

后续步骤