【问题标题】:Type definition - cannot use basic type as custom type even though basic type is source of custom type类型定义 - 即使基本类型是自定义类型的来源,也不能将基本类型用作自定义类型
【发布时间】:2020-10-22 12:21:11
【问题描述】:

在下面的代码中,我们在第 5,6,7 行使用了type definition 语法:

package math

// Constructors and Selectors

type RationalNumber []int                      // Line 5
type Numerator int
type Denominator int

// Constructor - Construct a rational number x that represents n/d
func NewRationalNumber(n int, d int) RationalNumber {
    g := gcd(n, d) 
    return []int{n / g, d / g}             // Line 12
}

//Selector
func numer(x RationalNumber) Numerator {
    return x[0]                           // Line 17
}

//Selector
func denom(x RationalNumber) Denominator {
    return x[1]
}

return []int{n / g, d / g}不报错,

在哪里,

return x[0] & return x[1] 给出错误:

math/numbers.go:17:10: cannot use x[0] (type int) as type Numerator in return argument
math/numbers.go:22:10: cannot use x[1] (type int) as type Denominator in return argument

对于第 5、6、7 行中给定的 3 个类型定义,我理解第 17 行错误背后的原因,但是,

  1. 为什么第 12 行没有给出类似的错误?

  2. 如何解决这个错误?不改变函数的签名?

【问题讨论】:

    标签: go types


    【解决方案1】:

    定义的类型 RationalNumber 是从具有 int 类型元素的切片创建的,因此订阅已定义类型的实例会给出 int,而不是任何新定义的从 int 创建的类型。

    编译器不会抱怨第 12 行,因为语法是适合创建已定义类型的 slice literal(提示:新 slice 类型的元素是 int)。

    【讨论】:

    • 好的,同意。但正如您在回答中提到的那样,在同一行...... return []int{n / g, d / g} 正在返回 []int 类型,但不是 RationalNumber 类型。为什么编译器不抱怨这个?为什么编译器不期望签名为func NewRationalNumber(n int, d int) []int {}
    • RationalNumber 是一个切片,用于创建实例的适当切片文字是 []int{}
    • 在同一行......我也可以说,Numerator 是一个 int,但对于编译器,Numeratorint 是两种不同的类型。同样,RationalNumber[]int 也是两种不同的类型。因此,对于return []int{1,2} 语法,编译应该期望返回类型为[]int 而不是RationalNumber。不是吗?
    • 它们是不同的类型。但是RationalNumber 的元素仍然是int。切片文字语法是语法糖。
    • Re 1:是的,RationalNumber 的基础类型是 []int,因此可分配性可以双向工作,因为其中至少有一个不是定义的类型:var r RationalNumber = []int{}var s []int = RationalNumber{} 都可以工作.
    【解决方案2】:

    您返回的类型与函数定义中指定的类型不同。

    numer(x RationalNumber) Numerator为例

    numer(x RationalNumber) Numerator 接受RationalNumber 类型的变量,并预计返回Numerator 类型的变量。 问题是您返回的是 int 类型(因为 RationalNumber 是 ints 的 slice),但应该是 Numerator 类型。

    您可以重构代码以将RationalNumber 返回的int 转换为适当的类型。

    type RationalNumber []int                    
    type Numerator int
    type Denominator int
    
    func NewRationalNumber(n int, d int) RationalNumber {
        g := gcd(n, d) 
        return []int{n / g, d / g}  
    }
    
    func numer(x RationalNumber) Numerator {
        return Numerator(x[0])                     
    }
    
    func denom(x RationalNumber) Denominator {
        return Denominator(x[1])
    }
    

    我知道,我的问题是为什么没有必要做 RationalNumber([]int{n / g, d / g})?

    您不需要这样做,因为 []int{n/g, d/g} 已经是整数切片。

    type Numerator = int 语法正在解决错误。我不确定,Numerator = int 类型与 Numerator int 类型有何不同?不需要 Numerator(x[0])

    type Numerator = intint 的类型别名。这不会创建不同于 int 的新类型。

    type Numerator int 创建了一个名为Numerator 的新自定义类型,其源类型为intNumerator 可以转换为 int 但它不同于 int

    更多解释可以参考Type definitions vs Type Alias

    【讨论】:

    • 我知道,我的问题是......为什么没有必要做RationalNumber([]int{n / g, d / g})
    • @overexchange 你不需要这样做,因为[]int{n/g, d/g} 已经是一个整数切片。
    • type Numerator = int 语法正在解决错误。我不确定,type Numerator = inttype Numerator int 有何不同?无需Numerator(x[0])
    • @overexchange 这是因为type Numerator = inttype 的别名int。而type Numerator int 创建了一个名为Numerator 的新自定义类型,其源类型为intNumerator 可以转换为 int 但与 int 不同
    【解决方案3】:

    这个问题也困扰着我,所以这是我想出的答案。

    以你的函数为例:

    func NewRationalNumber(n int, d int) RationalNumber {
        g := gcd(n, d) 
        return []int{n / g, d / g}
    }
    

    根据函数签名,它应该返回RationalNumber类型,但实际上它返回int切片。它起作用的原因是类型[]int 可以分配给类型RationalNumber。具体来说,它满足第二个条件,mentioned in language spec:

    x 的类型 V 和 T 具有相同的底层类型,并且 V 或 T 中至少有一个不是定义的类型。

    满足这个条件,因为在这种情况下,我们只有一个定义类型(RationalNumber),另一个是复合类型([]int)。

    那么,为什么我们在定义下面的函数时会报错呢?:

    func numer(x RationalNumber) Numerator {
        return x[0]
    }
    

    类型Numerator 具有int 作为基础类型,我们返回int,这是预先声明的类型,所以它应该可以工作,对吧?不)事情是,虽然int 是预先声明的,但它仍然是定义的类型。正如language spec 中所述:

    为避免可移植性问题,所有数字类型都是已定义类型

    事实上,所有predeclared types,除了error,都是定义类型。

    【讨论】:

      猜你喜欢
      • 2019-11-06
      • 1970-01-01
      • 2021-04-24
      • 2021-03-26
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多