我正在使用gorm,它允许许多数据类型,例如int, uint, int8, uint8 ....

然后我在模板中有一个这样的插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
f["UNIX2STR"] = func(t interface{}, f string) string {
        switch t.(type) {
        case int:
            return time.Unix(int64(t.(int)), 0).Format(f)
        case uint:
            return time.Unix(int64(t.(uint)), 0).Format(f)
        case uint8:
            return time.Unix(int64(t.(uint8)), 0).Format(f)
        case *int:
            return time.Unix(int64(*t.(*int)), 0).Format(f)
        case *uint:
            return time.Unix(int64(*t.(*uint)), 0).Format(f)
        case *uint8:
            return time.Unix(int64(*t.(*uint8)), 0).Format(f)
        .....
        default:
            return""
        }
        // return time.Unix(int64(t), 0).Format(f)
    }

它将所有整数类型转换为格式化的字符串。
那我该怎么办呢? 列出所有gorm支持的int类型并将其强制转换为int64

我已经搜索了许多天,以解决方案将interface{}转换为它的真实类型而不使用类型断言,但是没有用。

  • 你应该做什么?你想达到什么目的?
  • @Flimzy我不想列出所有整数类型,并且只用一行就可以了。如return time.Unix(int64(t.(trueType)), 0).Format(f)。您没有在这里看到麻烦吗?使用单个功能,我至少要切换/切换8次才能完成一个简单的任务
  • @Flimzy I have searched many days for solution convert interface{} to its true type without using type assertion but didnt work.没读过这一行吗?
  • 我看不到麻烦,因为我看不到你想完成什么。您只关注特定的解决方案,但尚未解释问题。您需要该switch语句的原因是什么?您要达到的目标是什么?
  • 多年来,我一直使用Go来通过gorm和类似的库进行数据库访问,但从未感到像问题中那样需要大型switch语句。几乎可以肯定有一种解决问题的不同方法,但是在不知道目标的情况下很难说。换句话说,这看起来像XY问题。
  • @Flimzy我只是想避免在不使用switch / case的情况下将所有整数类型转换为字符串时出错。如果您可以提供其他方法,请执行此操作。我从其他语言切换到了Go,缺少通用名称会给我带来很多麻烦。这就是例子。
  • 在我看来,他可能正在将行结果写入映射,而不是直接写入结构,然后稍后自己进行转换。我之前做过此事,并开始获取[]uint8之类的类型,而不是我期望的类型
  • 您的目标是提供一种将Unix时间戳转换为格式化日期字符串的格式化功能。那是对的吗?

根据您的评论,听起来您正在考虑将任何数字类型转换为字符串。这可以通过fmt.Sprint轻松完成:

1
stringValue := fmt.Sprint(i) // i is any type

但这与GORM无关。

另一方面,如果您的问题是GORM返回的是不可预测的类型,则只需将select语句更改为始终返回字符串即可。例如,对于MySQL,类似:

1
SELECT CAST(someNumberColumn AS VARCHAR) AS stringColumn

要么

1
SELECT CAST(someNumberColumn AS INT) AS intColumn
  • Gorm支持指针类型和普通类型,日期时间字段可以是int*int,因此这意味着如果字段类型是指针,则模板函数无法将其转换为字符串
  • 我不知道您在谈论什么模板功能,但是由于此问题与模板无关,因此可能需要解决一个单独的问题。
  • 这是问题的一部分。您看到我在问题*int中提到了指针类型,而Sprint(*i)不适用于指针类型

我没有使用过gorm,但是我认为这样可以解决您的问题:

1
2
3
4
5
6
7
8
func formatUnix(t interface{}, f string) (string, error) {
    timestampStr := fmt.Sprint(t)
    timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
    if err != nil {
        return"", err
    }
    return time.Unix(timestamp, 0).Format(f), nil
}

它没有列出所有可能的类型,而是仅使用fmt.Sprint()interface{}转换为string,然后使用strconv.ParseInt()string转换为int64


我认为这不是go或gorm的问题。我为将unix时间戳保存为许多不同格式而感到困惑。顺便说一句,unix时间戳是32位,因此转换(并保存在首位)任何8位int没有意义。

一种解决方案是对结构中的所有时间戳使用统一的数据类型(int64)。之后,格式化功能可以接受int64而不是interface{},而无需任何类型断言。

  • 我没有说这是gorm的问题。它的golang问题,它不支持泛型。这就是为什么我们必须使用switch / case来声明所有类型的原因。使用int64会导致内存。为什么我必须使用int64与字段只有0,1,2数字。这是设计模式,我们不能强迫其他开发人员在日期时间字段中仅使用int64,而gorm支持每种整数类型,这意味着任何人都可以在所需的任何字段中使用任何类型,因此逻辑代码必须处理所有它的。
  • 我不建议对所有数字字段使用int64。只需将其用于时间戳即可。如果您担心内存,可以使用int32,但是对于unix时间戳,它应该至少为32位。打印出任何其他数字作为格式化的日期字符串实际上没有任何意义,还是我遗漏了一些东西?因为有可能,并不意味着您应该使用它。为什么要对相同类型的数据使用任意数量的数据类型?指定所有时间戳以32位保存是明智的惯例。然后,您的函数可以接受int32而不是interface{}
  • 有数百万的代码逻辑。类似于上面的示例:将unixtimestamp(整数数据字段)转换为格式化的字符串。从那时起,gorm支持所有类型的整数。您将如何解决此问题?就像我说的那样,明智的约定或常识是基于每个开发人员的观点,并非每个人都具有相同的编码风格,为了行善,我们必须将所有情况都包含在代码逻辑中。使用Sprint实际上是一个不错的技巧,但不是解决拥有泛型之类问题的正确方法
  • 抱歉,我只是想提供帮助。我试图以我的知识和理解来回答您的问题。