繁体   English   中英

Go中文字类型的推断与混淆

[英]Confusion with type inference of literals in Go

我已经开始学习GoLang,目前正在阅读有关使用短变量声明语法的类型推断系统的信息。

这是一个简单的程序,引起了我的注意,并且使我难以理解:

package main

import (
    "fmt"
    "sort"
)

type statistics struct {
    numbers []float64
    mean    float64
    median  float64
}

// Performs analytics on a slice of floating-point numbers
func GenerateStats(numbers []float64) (stats statistics) {
    stats.numbers = numbers
    stats.mean = sum(numbers) / float64(len(numbers))
    sort.Float64s(numbers)
    stats.median = median(numbers)
    return stats
}

// Helper function to sum up a slice of floats
func sum(numbers []float64) (total float64) {
    for _, num := range numbers {
        total += num
    }
    return total
}

// Helper to find the median of a sorted slice of floats
func median(numbers []float64) (med float64) {
    n := len(numbers)
    if n%2 == 0 {
        med = numbers[n/2]
    } else {
        med = (numbers[n/2] + numbers[(n-1)/2]) / 2 // Infer 01
    }
    return med
}

func main() {
    nums := []float64{1, 2, 3, 3, 4}
    result := generateStats(nums)
    fmt.Println(result.numbers)
    fmt.Println(result.mean)
    fmt.Println(result.median)

    b := "This is Go" + 1.9 // Infer 02
    fmt.Println(b)
}

当我使用以下命令执行该程序时: $ go run <path>/statistics.go
我收到以下错误消息:

# command-line-arguments
<path>/statistics.go:47:20: cannot convert "This is Go" to type float64
<path>/statistics.go:47:20: invalid operation: "This is Go" + 1.9 (mismatched types string and float64)

这是行为不同的原因:

Infer 01 :数字文字2的类型是根据其使用的表达式来推断的。由于分子的类型为float64 ,因此Go假定对应类型的2为成功进行除法。 因此,LHS上的变量类型为float64

我对Infer 02使用了相同的推理:根据声明来推断float字面量1.9的类型。 但是,除非将浮点文字立即隐式转换为字符串,否则无法将其添加到字符串。 因此,我不确定变量b的类型。 因此,应该提出一个错误。

现在,我对错误消息感到困惑。

为什么编译器尝试将字符串文字隐式转换为float64类型?

在一般意义上:当两个操作数都是文字时,编译器如何推断类型? 有什么好的资源可以帮助我更好地理解Go的类型推断系统?

它不会尝试将其转换为float64类型。 它只是警告字符串文字不是float64

它可能说字符串不是浮点数,或者说float不是字符串,但是第二行涵盖了两种情况,即消息mismatched types string and float64

Go中的文字和常量没有Go类型。 例如:

  • 1.1234视为float常数(而不是float32float64
  • 2作为int常数
  • "hi"作为字符串常量。

当您尝试将常量放入变量中时,Go会根据变量类型尝试将常量适合变量:

type DayCount int
const i = 123456

var a int32 = i
var b uint64 = i
var c int = i
var d int8 = i  // compile error: constant 123456 overflows int8
var e DayCount = i
var f DayCount = c  // compile error: cannot use c (type int) as type DayCount in assignment

如果变量本身没有类型,而赋值的右侧是一个常量,则编译器将假定该常量的“默认类型”。 对于int常量,这是int类型;对于float常量,这是float64

var a = 1234          // a type will be int
var b = 1.1234567890  // b type will be float64
var c = "gogogo"      // c type will be string

您还可以对常量进行一些操作(在将它们转换为普通的go变量之前),该操作在编译时完成:

var a int8 = 25 * 87  // compile error: constant 2175 overflows int8

由于25和87都是常量,因此编译器将在编译程序时将它们倍增,并尝试将其放入失败的变量a中。 要点是,在运行程序时未完成乘法。

如果尝试混合使用普通变量和常量,则编译器将尝试将常量转换为变量类型:

var a uint64 = 87
var b = 25 * a
// Is the same as
var b = uint64(25) * a
// so b type is uint64

现在关于您问题中的第一种情况

med = (numbers[n/2] + numbers[(n-1)/2]) / 2 // Infer 01

是相同的

med = (numbers[n/int(2)] + numbers[(n-int(1))/int(2)]) / float64(2)

编译器将尝试将常量转换为附近的变量类型。 第一和第二2正在与int的除法运算中使用,并转换为int 第三个在与float64的除法中使用,并转换为float64 我认为“类型推断”不是这里的合适名称。

在第二种情况下,两个+运算符都是常量,编译器使用启发式方法,并假设如果其中一个常量是float,则两个常量都应适合float64 (这是有问题的),然后尝试将失败的字符串常量放入float64中(因此,无法转换为float64错误)。

第二种情况的行为未在规范中记录,我认为这根本不重要。 IMO有效的编译器可能会尝试将1.9装入字符串变量并显示另一个错误。

另请参见有关常量的博客,有关常量的 规范有关常量表达式的规范

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM