2017-12-07 18 views
-1

GoLang을 배우기 시작했으며 현재 짧은 변수 선언 구문을 사용하여 유형 유추 시스템에 대해 읽고 있습니다. 여기 Go에서 리터럴 유형 유추와 혼동

내 관심을 끌었 간단한 프로그램이며, 이해 좀 diffculty를 일으키는 :

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이 선언을 기반으로 유추됩니다. 그러나 float 리터럴은 암시 적으로 문자열로 변환되지 않는 한 문자열에 추가 할 수 없습니다. 따라서 변수 b의 유형이 확실하지 않습니다. 따라서 오류가 발생해야합니다.

이제 오류 메시지로 혼동합니다.

왜 컴파일러는 암시 적으로 문자열 리터럴을 float64 유형으로 변환하려고합니까?

일반적인 의미에서 : 피연산자가 모두 리터럴 인 경우 컴파일러에서 유형을 어떻게 추론합니까? Go의 유형 추론 시스템을 더 잘 이해하는 데 도움이되는 훌륭한 자료는 무엇입니까?

+0

Go는 수치 상수에 대해서만 리터럴 유형을 추론합니다. 그리고 숫자 형 ('int' 및'float'의 변형 및 별칭)에만 적용됩니다. 따옴표는 리터럴을 명시 적으로 문자열로 표시하고, 형식 유추가 필요하거나 수행되지 않습니다. – Kaedys

+2

여기에서 특별한 특별한 것을 만드는 것은 _constants_가 처리되는 방법 (리터럴)입니다. 그들은 기본적으로 완전히 다른 언어로 행동합니다. Go의 블로그 https://blog.golang.org/constants에서 상수 및 기본 유형을 읽으십시오. (실제로 타입 유추에 대해서는별로 중요하지 않습니다 .2는 상수, 1.9 상수 부동 소수점이고 "foo"는 상수입니다.) 상수를 주목하십시오. – Volker

+1

Kshitij 추론을 사용하고 있기 때문에 혼란스러워합니다. Go reasoning 사용 : Go 프로그래밍 언어 사양 : https://golang.org/ref/spec – peterSO

답변

2

float64 유형으로 변환하려고하지 않습니다. float64이 아닌 문자열 리터럴에 대해 경고합니다.

문자열이 float가 아니거나 float이 문자열이 아니지만 두 번째 줄에 메시지가있는 경우 모두 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이고 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 

또한 컴파일시에 수행되는 상수에 대한 몇 가지 작업을 할 수있는 : 있습니다

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) 

컴파일러는 근처의 변수 유형에 상수를 캐스트하려고 시도합니다. 첫 번째 및 두 번째 2int의 나누기 연산에 사용되며 int으로 변환됩니다. 세 번째 것은 float64이있는 division에서 사용되고 float64으로 변환됩니다. 나는 "타입 유추"가 여기에 적합한 이름이라고 생각하지 않습니다. 두 + 연산자 상수 번째 경우

는 컴파일러 경험적 접근법을 사용하여 정수의 플로트 경우 모두 상수 (즉 결함)을 float64에 적합해야한다는 가정에 문자열 상수를 배치하려고 시도 float64이 실패합니다 (따라서 float64 오류로 변환 할 수 없습니다).

두 번째 경우의 동작은 사양에 문서화되어 있지 않으며 전혀 문제가되지 않습니다. 올바른 컴파일러는 1.9을 문자열 변수에 넣으려고 시도 할 수 있으며 다른 오류가 표시됩니다.

도 참조하십시오. blog on constants, spec on constants, spec on constants expressions.