Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用F#和#x27;GetHashCode()中的哈希函数是什么?_Hash_F#_Equality_Gethashcode - Fatal编程技术网

使用F#和#x27;GetHashCode()中的哈希函数是什么?

使用F#和#x27;GetHashCode()中的哈希函数是什么?,hash,f#,equality,gethashcode,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 -> tr

我在网上遇到过几个地方的代码如下所示:

[<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
我不能轻易地证明它,但它表明,
hash x
调用对象上的
GetHashCode()
,这意味着上面的代码是危险的。还是只是FSI在渲染

我认为像上面这样的代码只是意味着“请实现自定义等式,但将哈希函数保留为默认值”

同时,我以不同的方式实现了这个模式,但我仍然怀疑我是否正确地假设
hash
只调用
GetHashCode()
,从而导致一个永恒的循环


另一方面,在FSI中使用equality会立即返回,这表明它要么在比较之前不调用
GetHashCode()
,要么执行其他操作。更新:这在上面的示例中是有意义的。Equals不调用
GetHashCode()
,并且equality操作符调用
Equals
,而不是
GetHashCode()

如果覆盖了
GetHashCode()
方法,则将使用该方法:

[code>散列运算符是一个]通用散列函数,用于根据=运算符为相等的项返回相等的散列值。默认情况下,它将对F#并集、记录和元组类型使用结构哈希,对类型的完整内容进行哈希。通过为每个类型实现System.Object.GetHashCode,可以逐个类型调整函数的确切行为


是的,这是一个坏主意,它会导致一个无限循环,这是有道理的。

它并不像
hash
函数简单地作为
GetHashCode
的包装器那样简单,但我可以轻松地告诉您,使用实现肯定是不安全的:
override x.GetHashCode()=hash x

如果通过跟踪
散列
函数,您将得到:

您可以在这里看到通配符case调用
x.GetHashCode()
,因此很可能会发现自己处于无限递归中

GetHashCode()
的实现中,我能看到的唯一一种可能需要使用
hash
的情况是手动对对象的某些成员进行哈希运算以生成哈希代码

在中有一个(非常古老的)示例,它以这种方式在
GetHashCode()
内部使用
hash


顺便说一下,这不是你发布的代码中唯一不安全的地方

object.Equals的重写绝对不能引发异常。如果类型不匹配,则返回false。这在
System.Object
中有明确的记录

Equals的实现不能抛出异常;他们应该 始终返回一个值。例如,如果obj为null,那么Equals方法 应返回false,而不是引发ArgumentNullException


()

“通过为每个类型实现System.Object.GetHashCode,可以逐个类型调整函数的确切行为。”,我也注意到了这一点,但它没有说它将调用
GetHashCode()。也就是说,写
x.GetHashCode()=如果x<0,那么0或者hash x
(也就是说,如果任何低于零的值都被认为是相等的),这是完全合理的。实际上,我希望
hash
调用
base.GetHashCode()
,这不会导致无限递归。@Abel它说,您可以通过重写
GetHashCode
来更改类型的
hash
函数的行为,如果它实际上没有调用
GetHashCode()
,它的行为会如何改变?听起来你是在解释这个句子,意思是“你可以在覆盖
GetHashCode
时使用
hash
函数”,这与它所说的正好相反。不完全一样。我的解释是,它允许特殊情况覆盖,其他情况下默认返回原始情况。但是我明白你的意思。“当你手动散列一个对象的一些成员时”,是的,这实际上是从创建一个可比较的函数类型开始的,类似于
string*('T->'U)
,在散列覆盖中,我对字符串调用了
hash s
(因此,这里没有无限递归)。但当我在网上看到这些帖子时,我想,嘿,让我们试试吧。。。引出这个问题。感谢您提供的指向源代码的指针。关于你对异常的评论:你是对的,错误的示例代码。。。我在胡闹。@Abel Yep,我想你可能知道这一点,但我认为值得向其他人指出这一点,因为这是一个很容易犯的常见小错误。你可以对我的
foo=bar
为真和
bar=foo
为假说同样的话,我认为这也是非常糟糕的做法;)。
let foo = Test.Foo;;
hash foo;;   // no returning to the console until Ctrl-break
foo.GetHashCode();;  // no return
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()