2017-12-07 20 views
-1

私はGoLangの学習を始めました。現在、短い変数宣言構文を使用して型推論システムについて読んでいます。Goでのリテラルの型推論との混乱

:私は、次のエラーメッセージが表示されます $ go run <path>/statistics.go
:私は使用してこのプログラムを実行すると

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) 
} 

:ここ

は私の注意を引いたし、私の理解では、いくつかのdiffcultyを引き起こしている単純なプログラムです

# 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と同じ推論を使用しました。 浮動小数点型の型1.9は、宣言に基づいて推論されます。ただし、暗黙的に文字列に変換されない限り、浮動小数点定数を文字列に追加することはできません。したがって、私は変数bのタイプについては不明です。したがって、エラーが発生する必要があります。

今、私はエラーメッセージで混乱しています。

なぜコンパイラは文字列リテラルをfloat64タイプに暗黙的に変換しようとしますか?

一般的には、両方のオペランドがリテラルの場合、コンパイラはどのように型を推測しますか? Goの型推論システムをより良く理解するのに役立つリソースはありますか?

+0

Goは、実際には数値定数に対してのみ、そして数値型( 'int'と' float'の変形とエイリアス)に対してのみ、リテラルの型を推論します。また、引用符はリテラルを文字列として明示的にマークすることに注意してください。型推論の必要性や完了はありません。 – Kaedys

+2

ここで特別な特別なことは、_constants_がどのように扱われるか(リテラル)です。基本的には、他の言語とはまったく異なっています。 Goのブログhttps://blog.golang.org/constantsで定数とそのデフォルトタイプを読んでください。 (実際には型推論についてはあまりよくありません.2は定数int、1.9は定数float、定数stringは "foo"です) – Volker

+1

Kshitij推論を使用しているので混乱します。 Go推論を使用する:Goプログラミング言語仕様:https://golang.org/ref/spec – peterSO

答えて

2

float64タイプに変換しようとしません。文字列リテラルがfloat64ではないことを警告します。

文字列が浮動小数点ではないか、または浮動小数点が文字列ではないと言えるかもしれませんが、2行目は両方のケースをメッセージmismatched types string and float64でカバーしています。

0

Goのリテラルと定数にはGo型がありません。たとえば、次のようにフロート定数として1.1234

  • 思う(とないfloat32またはfloat64
  • 2定数文字列として
  • "hi"定数intとして。変数自体は種類や権利を持っていない場合は

    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、浮動小数点定数の場合は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 

あなたはまた、コンパイル時に行われている定数にいくつかの操作を行うことができますされている

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 

は同じですas

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

コンパイラは、近くの可変型に定数をキャストしようとします。第1および第2の2は、intの除算演算で使用され、intに変換されます。 3番目はfloat64の部門で使用され、float64に変換されます。私は "型推論"はここのフィッティング名ではないと思います。両方+演算子は定数である第2のケースで

は、コンパイラは、発見的アプローチを使用し、定数のいずれかをフローティングである場合、両方の定数(つまり故障している) float64に適合されるべきであることを前提とに文字列定数を入れしようとし float64が失敗します(したがって、 float64エラーに変換できません)。

2番目のケースの動作は仕様に記載されていないため、まったく問題はないと思います。 IMOは、有効なコンパイラが文字列変数に1.9を収めようとする可能性があり、別のエラーを示します。

も参照blog on constants,spec on constants,spec on constants expressionsを参照してください。