You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

F#重载=与<>运算符判断结果不符合预期问题求解

F# 相等运算符重载问题修复

问题现象

  • 重载=、<>运算符时无法直接使用运算符符号作为成员名,收到编译器提示:
    1. 不应将名称'(=)'用作成员名。若要为类型定义相等语义,请重写Object.Equals成员;如果要定义供其他CLI语言使用的静态成员,请改用名称op_Equality。
    2. 不应将名称'(<>)'用作成员名。若要为类型定义相等语义,请重写Object.Equals成员;如果要定义供其他CLI语言使用的静态成员,请改用名称op_Inequality。
  • 按提示定义op_Equality、op_Inequality静态成员后编译通过,但运行结果不符合预期:实例化两个坐标均为(1, 0)的Point对象p1、p2时,p1 = p2返回false,p1 <> p2返回true。

原始错误实现代码:

open System

type Point(X : float, Y : float) =
  class
    member public this.X : float = X
    member public this.Y : float = Y
    static member public Origin : Point = Point(0.0, 0.0)
  
    static member public (+) (P1 : Point, P2 : Point) : Point =
      Point(P1.X+P2.X, P1.Y+P2.Y)
    
    static member public (-) (P1 : Point, P2 : Point) : Point =
      Point(P1.X-P2.X, P1.Y-P2.Y)
    
    static member public op_Equality (P1 : Point, P2 : Point) : bool =
      P1.X = P2.X && P1.Y = P2.Y
      
    static member public op_Inequality (P1 : Point, P2 : Point) : bool =
        P1.X <> P2.X && P1.Y <> P2.Y
    
    override this.ToString() = 
      String.Format("({0}, {1})", X, Y)
  end

错误原因

  • 逻辑错误:op_Inequality实现中错误使用了&&(逻辑与)运算符,当前逻辑要求X、Y坐标同时不相等才判定对象不等,正确逻辑应为只要任意一个坐标不相等就判定对象不等。
  • 语义不符合F#规则:编译器提示已经明确说明,F#中类型的相等语义优先通过重写Object.Equals实现,仅定义op_Equality静态成员不会覆盖F#原生=运算符的默认行为。当前=返回false是因为类类型默认做引用相等判断,两个分别实例化的对象引用地址不同,哪怕值一致也会被判定为不等。

修复方案

按F#的相等语义规范实现即可,需要完成三个修改:

  1. 重写Object.Equals方法,基于坐标值实现值相等判断
  2. 重写Object.GetHashCode方法,保证相等对象返回相同哈希码,避免哈希集合类操作出现异常
  3. 修正不等判断逻辑,op_Equality和op_Inequality直接复用Equals逻辑,避免重复代码写错判断条件

修复后的完整代码:

open System

type Point(X : float, Y : float) =
    member public this.X : float = X
    member public this.Y : float = Y
    static member public Origin : Point = Point(0.0, 0.0)
  
    static member public (+) (P1 : Point, P2 : Point) : Point =
        Point(P1.X+P2.X, P1.Y+P2.Y)
    
    static member public (-) (P1 : Point, P2 : Point) : Point =
        Point(P1.X-P2.X, P1.Y-P2.Y)
    
    override this.Equals(obj) =
        match obj with
        | :? Point as other -> this.X = other.X && this.Y = other.Y
        | _ -> false
    
    override this.GetHashCode() =
        HashCode.Combine(this.X, this.Y)
    
    static member op_Equality (P1 : Point, P2 : Point) =
        P1.Equals(P2)
      
    static member op_Inequality (P1 : Point, P2 : Point) =
        not (P1.Equals(P2))
    
    override this.ToString() = 
        String.Format("({0}, {1})", X, Y)

验证结果

执行测试代码:

let p1 = Point(1, 0)
let p2 = Point(1, 0)
printfn $"%b{p1 = p2}"  // 输出 true
printfn $"%b{p1 <> p2}" // 输出 false

结果符合预期。

内容的提问来源于stack exchange,提问作者user17682078

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:33:41