Trying to define generic methods to access a memory cache

86 views
Skip to first unread message

David Karr

unread,
Feb 12, 2025, 4:54:17 PM2/12/25
to golang-nuts
I don't expect this should be very difficult, go-wise, but I haven't written much code with generics yet.

I have an application that can read commits from either github or bitbucket, but each run will either be for bitbucket or github, not both.  I have to retrieve the commits for a branch a couple of times, so I have a "commitsCache" that is keyed by the project, repo, and branch.  All three of those have analogs in github and bitbucket.

For now, I've declared "BitbucketCommit" and "GithubCommit" structs. It's entirely possible I could merge them eventually, but I'll leave them separate for now.

I have this declaration:

commitsCache            = make(map[string][]any)

Note the element type of "any", not BitbucketCommit or GIthubCommit.  I assume this is correct.

I have both a "get" and "store" method. The following is what I have so far for the "get" method:
func getFromCommitsCache[T any](project string, repo string, branch string) ([]T, bool) {
    commitsCacheMutex.RLock()
    defer commitsCacheMutex.RUnlock()
    if commits, found := commitsCache[project+"/"+repo+"/"+branch]; found {
        if v, ok := commits.([]T); ok { // This line.
            return v, true
        }
    }
    return nil, false
}

I'm not quite sure what to do here. The line with "this line" has the following compile error:
invalid operation: commits (variable of type []any) is not an interfacecompilerInvalidAssert


I'm currently using Go v1.22.6 , although I could certainly upgrade, if there's a good reason to.

Jan Mercl

unread,
Feb 12, 2025, 5:15:03 PM2/12/25
to David Karr, golang-nuts
On Wed, Feb 12, 2025 at 10:54 PM David Karr <davidmic...@gmail.com> wrote:

`[]any` is a slice type (https://go.dev/ref/spec#Slice_types), not an
interface type (https://go.dev/ref/spec#Interface_types).

But type assertions, as in `expr.(someType)`, are valid only for
interface types: https://go.dev/ref/spec#Type_assertions

David Karr

unread,
Feb 12, 2025, 5:33:51 PM2/12/25
to golang-nuts
Ok, good to know. How do I solve this problem? It almost looks like I have to create a slice of the generic type and iterate through the entries in the commitsCache result, doing a type conversion of every entry.

David Karr

unread,
Feb 12, 2025, 5:51:17 PM2/12/25
to golang-nuts
So, for instance, this appears to compile, but I haven't run it yet:
func getFromCommitsCache[T any](project string, repo string, branch string) ([]T, bool) {
    commitsCacheMutex.RLock()
    defer commitsCacheMutex.RUnlock()
    var result []T
    if commits, found := commitsCache[project+"/"+repo+"/"+branch]; found {
        for _, commit := range commits {
            result = append(result, commit.(T))
        }
        return result, true
    }
    return nil, false
}

func storeToCommitsCache[T any](project string, repo string, branch string, commits []T) {
    commitsCacheMutex.Lock()
    defer commitsCacheMutex.Unlock()
    var anyResult []any
    for _, commit := range commits {
        anyResult = append(anyResult, commit)
    }
    commitsCache[project+"/"+repo+"/"+branch] = anyResult
}


Jan Mercl

unread,
Feb 12, 2025, 5:53:19 PM2/12/25
to David Karr, golang-nuts
On Wed, Feb 12, 2025 at 11:34 PM David Karr <davidmic...@gmail.com> wrote:
>
> Ok, good to know. How do I solve this problem? It almost looks like I have to create a slice of the generic type and iterate through the entries in the commitsCache result, doing a type conversion of every entry.

I don't know what problem your code tries to solve. Anyway, a
simplified, possibly unusable example :
https://go.dev/play/p/NTngATo1lIU
Reply all
Reply to author
Forward
0 new messages