// Copyright (c) 2025 GeWuYou
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace GFramework.Core.functional;
///
/// 表示可能存在或不存在的值,用于替代 null 引用的函数式编程类型
///
/// 值的类型
public readonly struct Option
{
private readonly T _value;
private readonly bool _isSome;
///
/// 私有构造函数,用于创建 Some 状态
///
private Option(T value)
{
_value = value;
_isSome = true;
}
///
/// 判断是否有值
///
public bool IsSome => _isSome;
///
/// 判断是否无值
///
public bool IsNone => !_isSome;
#region 工厂方法
///
/// 创建包含值的 Option
///
/// 要包装的值
/// 包含值的 Option
/// 当 value 为 null 时抛出
///
///
/// var option = Option<int>.Some(42);
///
///
public static Option Some(T value)
{
ArgumentNullException.ThrowIfNull(value);
return new Option(value);
}
///
/// 表示无值的 Option
///
public static Option None => default;
#endregion
#region 取值
///
/// 获取值,如果无值则返回默认值
///
/// 无值时返回的默认值
/// Option 中的值或默认值
///
///
/// var value = option.GetOrElse(0); // 如果无值则返回 0
///
///
public T GetOrElse(T defaultValue) => _isSome ? _value : defaultValue;
///
/// 获取值,如果无值则通过工厂函数生成默认值
///
/// 生成默认值的工厂函数
/// Option 中的值或工厂函数生成的值
/// 当 factory 为 null 时抛出
///
///
/// var value = option.GetOrElse(() => ExpensiveDefault());
///
///
public T GetOrElse(Func factory)
{
ArgumentNullException.ThrowIfNull(factory);
return _isSome ? _value : factory();
}
#endregion
#region 变换
///
/// 映射值到新类型,如果无值则返回 None
///
/// 映射后的类型
/// 映射函数
/// 映射后的 Option
/// 当 mapper 为 null 时抛出
///
///
/// var option = Option<int>.Some(42);
/// var mapped = option.Map(x => x.ToString()); // Option<string>.Some("42")
///
///
public Option Map(Func mapper)
{
ArgumentNullException.ThrowIfNull(mapper);
return _isSome ? Option.Some(mapper(_value)) : Option.None;
}
///
/// 单子绑定操作,将 Option 链式转换
///
/// 绑定后的类型
/// 绑定函数
/// 绑定后的 Option
/// 当 binder 为 null 时抛出
///
///
/// var option = Option<string>.Some("42");
/// var bound = option.Bind(s => int.TryParse(s, out var i)
/// ? Option<int>.Some(i)
/// : Option<int>.None);
///
///
public Option Bind(Func> binder)
{
ArgumentNullException.ThrowIfNull(binder);
return _isSome ? binder(_value) : Option.None;
}
#endregion
#region 过滤
///
/// 根据条件过滤值,不满足条件则返回 None
///
/// 过滤条件
/// 满足条件的 Option 或 None
/// 当 predicate 为 null 时抛出
///
///
/// var option = Option<int>.Some(42);
/// var filtered = option.Filter(x => x > 0); // Option<int>.Some(42)
/// var filtered2 = option.Filter(x => x < 0); // Option<int>.None
///
///
public Option Filter(Func predicate)
{
ArgumentNullException.ThrowIfNull(predicate);
return _isSome && predicate(_value) ? this : None;
}
#endregion
#region 模式匹配
///
/// 模式匹配,根据是否有值执行不同的函数
///
/// 返回值类型
/// 有值时执行的函数
/// 无值时执行的函数
/// 匹配结果
/// 当 some 或 none 为 null 时抛出
///
///
/// var result = option.Match(
/// some: value => $"Value: {value}",
/// none: () => "No value"
/// );
///
///
public TResult Match(Func some, Func none)
{
ArgumentNullException.ThrowIfNull(some);
ArgumentNullException.ThrowIfNull(none);
return _isSome ? some(_value) : none();
}
///
/// 模式匹配(副作用版本),根据是否有值执行不同的操作
///
/// 有值时执行的操作
/// 无值时执行的操作
/// 当 some 或 none 为 null 时抛出
///
///
/// option.Match(
/// some: value => Console.WriteLine($"Value: {value}"),
/// none: () => Console.WriteLine("No value")
/// );
///
///
public void Match(Action some, Action none)
{
ArgumentNullException.ThrowIfNull(some);
ArgumentNullException.ThrowIfNull(none);
if (_isSome)
some(_value);
else
none();
}
#endregion
#region 转换
///
/// 转换为 Result 类型
///
/// 无值时的错误消息
/// Result 类型
///
///
/// var result = option.ToResult("Value not found");
///
///
public Result ToResult(string errorMessage = "Value is None")
{
ArgumentException.ThrowIfNullOrWhiteSpace(errorMessage);
return _isSome
? Result.Succeed(_value)
: Result.Fail(new InvalidOperationException(errorMessage));
}
///
/// 转换为可枚举集合(有值时包含一个元素,无值时为空集合)
///
/// 可枚举集合
///
///
/// var items = option.ToEnumerable(); // 有值时: [value], 无值时: []
///
///
public IEnumerable ToEnumerable()
{
if (_isSome)
yield return _value;
}
#endregion
#region 隐式转换
///
/// 从值隐式转换为 Option
///
public static implicit operator Option(T value) =>
value is not null ? Some(value) : None;
#endregion
#region 相等性和比较
///
/// 判断两个 Option 是否相等
///
public bool Equals(Option other)
{
if (_isSome != other._isSome)
return false;
return !_isSome || EqualityComparer.Default.Equals(_value, other._value);
}
///
/// 判断与对象是否相等
///
public override bool Equals(object? obj) =>
obj is Option other && Equals(other);
///
/// 获取哈希码
///
public override int GetHashCode() =>
_isSome ? EqualityComparer.Default.GetHashCode(_value!) : 0;
///
/// 相等运算符
///
public static bool operator ==(Option left, Option right) =>
left.Equals(right);
///
/// 不等运算符
///
public static bool operator !=(Option left, Option right) =>
!left.Equals(right);
#endregion
#region 字符串表示
///
/// 获取字符串表示
///
public override string ToString() =>
_isSome ? $"Some({_value})" : "None";
#endregion
}