Can a struct be made comparable?

1,216 views
Skip to first unread message

Mark

unread,
Jul 13, 2023, 4:29:38 AM7/13/23
to golang-nuts
I have a package which has a function `Do[T comparable](a, b []T) Result`.
I have a struct:
```go
type N struct {
  x int
  y int
  t string
}
```
Is it possible to make `N` comparable; in particular by a field of my choice, e.g., `t`?

Or will I have to make, say, `DoFunc(a, b []N, eq func(i, j N) bool) Result` with, say,
`func eq(i, j N) { return i.t == j.t }`?

Brian Candler

unread,
Jul 13, 2023, 5:06:01 AM7/13/23
to golang-nuts
Structs are already comparable, but all fields must be the same:
I think your solution with function 'eq' is fine.  You can see the same thing in the standard library in slices.CompactFunc and slices.EqualFunc

For the case of "ordered" rather than "comparable", have a look at slices.BinarySearchFunc and related functions.

Peter Galbavy

unread,
Jul 14, 2023, 3:31:39 AM7/14/23
to golang-nuts
As a slight digression - I thought I was going mad, but 'slices' and 'maps' are new :-) Only in 1.21 though...

Well, there is a lot of boiler plate that maps.Keys() will get rid of.

Mark

unread,
Jul 14, 2023, 3:58:41 AM7/14/23
to golang-nuts
What I really want to do is to be able to diff slices of structs on the basis of one single field.
For example, given:
```
type Item struct {
  I int
  S string
}
```
and given `a` and `b` are both of type`[]Item`, I want to diff these slices based purely on the `S` field, ignoring the `I` field.

This diff pkg claims to be able to do this (something I'm testing, so I don't know either way yet), but in any case, it is incredibly slow.

Mark

unread,
Jul 14, 2023, 4:11:35 AM7/14/23
to golang-nuts
In fact the diff pkg mentioned above does work but is of no use to me since for each change it gives back only the field(s) used, not the original structs (or pointers to them), so I can't see any way back to the original structs (or their slice indexes).

Brian Candler

unread,
Jul 14, 2023, 4:47:21 AM7/14/23
to golang-nuts
You seem to be saying "if the S field is different then I want to consider these two structs different, and get pointers to the two structs. If the S field is the same then I want to skip the pair entirely". Is that right?

The required semantics are not entirely clear, but it sounds like a handful of lines of code to implement - there's no point importing and learning a third party library.

On the assumption that all the elements to be compared are in corresponding positions in a and b:

Brian Candler

unread,
Jul 14, 2023, 5:00:34 AM7/14/23
to golang-nuts
I forgot you wanted generics:

Mark

unread,
Jul 14, 2023, 5:47:47 AM7/14/23
to golang-nuts
Hi Brian,
Your code certainly identifies the different items.
However, that's not a diff tool in the sense I mean.
Unix diff and tools like it don't just say x[i] != y[i], they find the longest common subsequences and in essence produce a series of edit commands that would turn slice x into slice y.
There are quite a few go diff tools that will do this, including my own based on Python's difflib sequence matcher.
What I want to do is find one that does this for slices of structs where only one struct field is considered for comparison purposes.

Brian Candler

unread,
Jul 14, 2023, 6:54:51 AM7/14/23
to golang-nuts
The 'diff' package you showed identifies the changed object index by means of a "Path" attribute in the Changelog entry. If the top level object is a slice, then Atoi(change.Path[0]) is the index into the slice.

Mark

unread,
Jul 14, 2023, 7:27:46 AM7/14/23
to golang-nuts
Hi Brian,
Ah, thank you, that helped a lot.

Mark

unread,
Jul 14, 2023, 3:58:45 PM7/14/23
to golang-nuts
I finally worked out how to make my go-diff pkg (v1.1.0) able to diff sequences of structs based on a key function.
Reply all
Reply to author
Forward
0 new messages