Abe*_*bel 4 hash f# equality gethashcode
我在网上遇到过几个代码看起来像这样的地方:
[<CustomEquality;NoComparison>]
type Test =
| Foo
| Bar
override x.Equals y =
match y with
| :? Test as y' ->
match y' with
| Foo -> false
| Bar -> true // silly, I know, but not the question here
| _ -> failwith "error" // don't do this at home
override x.GetHashCode() = hash x
Run Code Online (Sandbox Code Playgroud)
但是当我在FSI中运行上面的操作时,当我调用hash foo实例Test或foo.GetHashCode()直接调用时,提示不会返回.
let foo = Test.Foo;;
hash foo;; // no returning to the console until Ctrl-break
foo.GetHashCode();; // no return
Run Code Online (Sandbox Code Playgroud)
我无法轻易证明它,但它表明对对象的hash x调用GetHashCode(),这意味着上面的代码是危险的.或者仅仅是FSI在玩吗?
我认为上面的代码只是意味着"请实现自定义相等,但将哈希函数保留为默认值".
我同时以不同的方式实现了这种模式,但我仍然想知道我是否正确假设hash只是调用GetHashCode(),导致一个永恒的循环.
顺便说一句,在FSI中使用相等性会立即返回,这表明它更新:这是有道理的,因为在上面的示例GetHashCode()在比较之前不会调用,或者它会执行其他操作.x.Equals中没有调用GetHashCode(),而相等运算符调用Equals,而不是调用GetHashCode().
它并不像hash函数只是一个包装器那么简单,GetHashCode但我可以很容易地告诉你,使用这个实现绝对不安全:override x.GetHashCode() = hash x.
如果你追踪这个hash功能,你最终会到这里:
let rec GenericHashParamObj (iec : System.Collections.IEqualityComparer) (x: obj) : int =
match x with
| null -> 0
| (:? System.Array as a) ->
match a with
| :? (obj[]) as oa -> GenericHashObjArray iec oa
| :? (byte[]) as ba -> GenericHashByteArray ba
| :? (int[]) as ba -> GenericHashInt32Array ba
| :? (int64[]) as ba -> GenericHashInt64Array ba
| _ -> GenericHashArbArray iec a
| :? IStructuralEquatable as a ->
a.GetHashCode(iec)
| _ ->
x.GetHashCode()
Run Code Online (Sandbox Code Playgroud)
你可以在这里看到通配符案例调用x.GetHashCode(),因此很有可能发现自己处于无限递归状态.
我可以看到你可能想要hash在一个实现中使用的唯一情况GetHashCode()是当你手动散列一些对象的成员来产生哈希码时.
在Don Syme的WebLog中有一个(非常古老的)以这种方式使用hash内部的例子.GetHashCode()
顺便说一下,这并不是你发布的代码唯一不安全的东西.
覆盖object.Equals绝对不能抛出异常.如果类型不匹配,则返回false.这清楚地记录在中System.Object.
Equals的实现不得抛出异常; 他们应该总是返回一个值.例如,如果obj为null,则Equals方法应返回false而不是抛出ArgumentNullException.
(来源)
| 归档时间: |
|
| 查看次数: |
420 次 |
| 最近记录: |