如何使用自定义类类型作为Swift中Dictionary的键?

时间:2022-05-07 16:28:14

I am working on a project built by using Swift, and I am trying to create a dictionary to store objects of a custom class called Pixel(KEY, for storing colour information such as RGB values) and int values (Value, for counting how many times the same colour appearing on the same image).

我正在研究一个使用Swift构建的项目,我正在尝试创建一个字典来存储一个名为Pixel的自定义类的对象(KEY,用于存储RGB值等颜色信息)和int值(Value,用于计算多少相同颜色出现在同一图像上的次数)。

If this is in C#, the working code should be:

如果这是在C#中,则工作代码应为:

Dictionary<Pixel, int> colorDictionary = new Dictionary< Pixel, int> ();

Dictionary colorDictionary = new Dictionary (); ,int> ,int>

In Swift, I tried:

在Swift中,我尝试过:

var colorDictionary = Dictionary<Pixel, Int>()

However, the error I got:

但是,我得到的错误:

"Type 'Pixel' does not conform to protocol 'Hashable'"

“类型'Pixel'不符合协议'Hashable'”

What should I do to solve this? Thanks very much!

我该怎么做才能解决这个问题?非常感谢!

3 个解决方案

#1


3  

Any custom type that you want to use a dictionary key must conform with the Hashable protocol.

要使用字典键的任何自定义类型都必须符合Hashable协议。

This protocol has one property that you must implement.

此协议有一个必须实现的属性。

var hashValue: Int { get }

var hashValue:Int {get}

Use this property to generate an int that Dictionary can use for lookup reasons. You should try to make it so the generated hashValue is unique for each pixel.

使用此属性可生成Dictionary可用于查找原因的int。您应该尝试使其生成的hashValue对于每个像素都是唯一的。

The Swift book has the following note, so you can probably make a random hash (as long as it's unique):

Swift书中有以下注释,因此您可以创建一个随机哈希(只要它是唯一的):

The value returned by a type's hashValue property is not required to be the same across different executions of the same program, or in different programs.

类型的hashValue属性返回的值在同一程序的不同执行或不同程序中不需要相同。

Note that because Hashable inherits from Equatable you must also implement:

请注意,因为Hashable继承自Equatable,您还必须实现:

func ==(_ lhs: Self, _ rhs: Self) -> Bool.

I'm not sure what the internal structure of your pixel is, but you could probably consider two pixels equal when both have the same "x" and "y" values. The final logic is up to you.

我不确定像素的内部结构是什么,但是当两者具有相同的“x”和“y”值时,你可能会认为两个像素相等。最后的逻辑取决于你。

Modify this as you need:

根据需要修改:

struct Pixel : Hashable {

    // MARK: Hashable
    var hashValue: Int {
        get {
            // Do some operations to generate a unique hash.
        }
    }
}

//MARK: Equatable
func ==(lh: Pixel, rh: Pixel) -> Bool {
    return lh.x == rh.x && rh.y == lh.y
}

#2


3  

Continuing on with what Andy Ibanez posted. A shortcut to implementing a hashValue is to piggyback off String's hashValue. You could do something like this.

继续Andy Ibanez发布的内容。实现hashValue的快捷方式是捎带String的hashValue。你可以这样做。

class Pixel: Hashable {
    var r:Int = 0;
    var g:Int = 0;
    var b:Int = 0;
    var a:Int = 0;

    var hashValue: Int {
        get {
            return "\(r)\(g)\(b)\(a)".hashValue;
        }
    }
}

You also need an Equatable function because hashValues in this case are merely a quick check for verifying two objects are not equal. Since it is possible for two objects to have the same hashValue, but not be equal, you still need to implement == to define equality like below.

您还需要一个Equatable函数,因为在这种情况下,hashValues只是用于验证两个对象不相等的快速检查。由于两个对象可能具有相同的hashValue但不相等,因此您仍需要实现==以定义如下所示的相等性。

func ==(lhs: Pixel, rhs: Pixel) -> Bool{
    if lhs.r != rhs.r{
        return false;
    }
    if lhs.g != rhs.g{
        return false;
    }
    if lhs.b != rhs.b{
        return false;
    }
    if lhs.a != rhs.a{
        return false;
    }
    return true;
}

#3


1  

Implement the Hashable protocol like this:

像这样实现Hashable协议:

class Pixel : Hashable {
    var alpha, red, green, blue : Int

    init(red: Int, green: Int, blue: Int, alpha: Int) {
        self.red = red
        self.green = green
        self.blue = blue
        self.alpha = alpha
    }

    var hashValue : Int {
        get {
            return alpha ^ red ^ green ^ blue
        }
    }
}

func ==(lhs: Pixel, rhs: Pixel) -> Bool {
    return lhs.alpha == rhs.alpha && lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue
}

#1


3  

Any custom type that you want to use a dictionary key must conform with the Hashable protocol.

要使用字典键的任何自定义类型都必须符合Hashable协议。

This protocol has one property that you must implement.

此协议有一个必须实现的属性。

var hashValue: Int { get }

var hashValue:Int {get}

Use this property to generate an int that Dictionary can use for lookup reasons. You should try to make it so the generated hashValue is unique for each pixel.

使用此属性可生成Dictionary可用于查找原因的int。您应该尝试使其生成的hashValue对于每个像素都是唯一的。

The Swift book has the following note, so you can probably make a random hash (as long as it's unique):

Swift书中有以下注释,因此您可以创建一个随机哈希(只要它是唯一的):

The value returned by a type's hashValue property is not required to be the same across different executions of the same program, or in different programs.

类型的hashValue属性返回的值在同一程序的不同执行或不同程序中不需要相同。

Note that because Hashable inherits from Equatable you must also implement:

请注意,因为Hashable继承自Equatable,您还必须实现:

func ==(_ lhs: Self, _ rhs: Self) -> Bool.

I'm not sure what the internal structure of your pixel is, but you could probably consider two pixels equal when both have the same "x" and "y" values. The final logic is up to you.

我不确定像素的内部结构是什么,但是当两者具有相同的“x”和“y”值时,你可能会认为两个像素相等。最后的逻辑取决于你。

Modify this as you need:

根据需要修改:

struct Pixel : Hashable {

    // MARK: Hashable
    var hashValue: Int {
        get {
            // Do some operations to generate a unique hash.
        }
    }
}

//MARK: Equatable
func ==(lh: Pixel, rh: Pixel) -> Bool {
    return lh.x == rh.x && rh.y == lh.y
}

#2


3  

Continuing on with what Andy Ibanez posted. A shortcut to implementing a hashValue is to piggyback off String's hashValue. You could do something like this.

继续Andy Ibanez发布的内容。实现hashValue的快捷方式是捎带String的hashValue。你可以这样做。

class Pixel: Hashable {
    var r:Int = 0;
    var g:Int = 0;
    var b:Int = 0;
    var a:Int = 0;

    var hashValue: Int {
        get {
            return "\(r)\(g)\(b)\(a)".hashValue;
        }
    }
}

You also need an Equatable function because hashValues in this case are merely a quick check for verifying two objects are not equal. Since it is possible for two objects to have the same hashValue, but not be equal, you still need to implement == to define equality like below.

您还需要一个Equatable函数,因为在这种情况下,hashValues只是用于验证两个对象不相等的快速检查。由于两个对象可能具有相同的hashValue但不相等,因此您仍需要实现==以定义如下所示的相等性。

func ==(lhs: Pixel, rhs: Pixel) -> Bool{
    if lhs.r != rhs.r{
        return false;
    }
    if lhs.g != rhs.g{
        return false;
    }
    if lhs.b != rhs.b{
        return false;
    }
    if lhs.a != rhs.a{
        return false;
    }
    return true;
}

#3


1  

Implement the Hashable protocol like this:

像这样实现Hashable协议:

class Pixel : Hashable {
    var alpha, red, green, blue : Int

    init(red: Int, green: Int, blue: Int, alpha: Int) {
        self.red = red
        self.green = green
        self.blue = blue
        self.alpha = alpha
    }

    var hashValue : Int {
        get {
            return alpha ^ red ^ green ^ blue
        }
    }
}

func ==(lhs: Pixel, rhs: Pixel) -> Bool {
    return lhs.alpha == rhs.alpha && lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue
}