ForcePilot/backend/package/yuxi/channels/contract/dtos/option.py

86 lines
2.4 KiB
Python
Raw Normal View History

"""Option 类型:显式表示"无结果"语义。
替代 ``T | None`` 表示"无结果"的隐式语义遵循 §7.3"端口不得返回 null
表示'无结果'"。提供 ``Some[T]`` 与 ``Nothing`` 两个不可变值,调用方通过
``is_some()`` / ``is_nothing()`` / ``unwrap()`` / ``unwrap_or(default)``
方法安全访问
关联约束CON-015 / CON-019 / CON-021 / CON-027被驱动端口不得以
``T | None`` 表示"无结果"
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import NoReturn, TypeVar
from yuxi.channels.contract.errors import InternalError
T = TypeVar("T")
@dataclass(frozen=True)
class Some[T]:
"""有值的 Option。
字段
value: 被包装的实际值
"""
value: T
def is_some(self) -> bool:
"""是否为有值状态。"""
return True
def is_nothing(self) -> bool:
"""是否为无值状态。"""
return False
def unwrap(self) -> T:
"""取出内部值。"""
return self.value
def unwrap_or(self, default: T) -> T:
"""取出内部值,无值时返回默认值(``Some`` 始终有值,故忽略 default"""
return self.value
@dataclass(frozen=True)
class Nothing:
"""无值的 Option。
值相等语义无字段 frozen dataclass任意两个 ``Nothing`` 实例相等且
可哈希用于替代 ``None`` 表示"无结果"由端口在未查询到结果时返回
"""
def is_some(self) -> bool:
"""是否为有值状态。"""
return False
def is_nothing(self) -> bool:
"""是否为无值状态。"""
return True
def unwrap(self) -> NoReturn:
"""取出内部值。
@raise InternalError ``Nothing`` 无内部值 ``Nothing`` 上调用
``unwrap()`` 属于编程误用抛出契约层 ``InternalError``
"""
raise InternalError(message="Cannot unwrap Nothing")
def unwrap_or[T](self, default: T) -> T:
"""取出内部值,无值时返回默认值。
@param default: 默认值
@return 默认值
"""
return default
# Option 类型别名:``Some[T] | Nothing``,供端口签名使用。
# 通过 PEP 695 ``type`` 语句声明泛型别名,``Option[str]`` 等下标用法
# 可被类型检查器识别为 ``Some[str] | Nothing``。
type Option[T] = Some[T] | Nothing