2017-04-26 6 views
0

私は、1つのパラメータを定義して、タイプがfunc(interface{}, proto.Message) interface{}であるインターフェースを持っていて、タイプfunc reduceMsg(a interface{}, b proto.Message) []*PersistentDataを渡そうとしています。これにより、次のコンパイラエラーが発生します。指定された戻り値のサブタイプ(この場合はインタフェース{})を返すにはどうすればよいですか?

Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{} 

このエラーの原因とその回避方法を教えてください。 interface{}よりも具体的なタイプを返すように思われます。問題を説明する単純な完全な例を次に示します。

package main 

import "fmt" 

func main() { 
    var t func() interface{} = func() []string { return []string{} } 
    fmt.Println(t) 
} 
+2

https://golang.org/doc/faq#covariant_types – JimB

+0

これは言語の欠陥のようです。特に次のことが完全に合法であることを考えると、 'var t interface {} = [] string {}'です。 – jonderry

+1

あなたの例は実際に説明された問題とは関係ありません。割り当てルール(サンプルコード)とインターフェイス実装ルール(実際の問​​題)は異なります。 – zerkms

答えて

1

Referencing the spec

In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:

  • Any typed value may be assigned to the blank identifier.
  • If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
  • If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.

Assignability

A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:

  • x's type is identical to T.
  • x's type V and T have identical underlying types and at least one of V or T is not a named type.
  • T is an interface type and x implements T.
  • x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
  • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
  • x is an untyped constant representable by a value of type T.

、移動はあなたが暗黙的に使用することができるという例外を除いて、ある型から別の型の値を変換することはできませんコンクリート型付けされたオブジェクトは、あたかもそれらが実装しているインタフェースであるかのように見えます。

実際には関数がinterface{}を返さないため、コンパイラは戻り値をinterface{}としてまとめて返す必要があります。

基本的には(明示的に)あなたはランタイムが暗黙のうちにやりたいラッピング操作を行っている
type Foo struct { 
    X int 
} 
func create(x int) Foo { 
    return Foo{X: x} 
} 
func main() { 
    var f func(int) interface{} = func(x int) interface{} { 
     return create(x) 
    } 
} 

を:あなたは本当にあなたが明示的に自分でこれを行うことができますしようとしているものを達成したい場合。

2

オブジェクトのタイプは関数シグネチャ全体です。署名が一致しない場合、それは同じタイプではなく、そのように割り当てられません。

すべての型がインターフェイスを満たしているため、何も空のインターフェイスに割り当てることはできますが、どちらの型も空のインターフェイスではなく、空のインターフェイスを返すだけです。

機能の一部を別の機能に割り当てることはできないため、機能の一部を同じにすることはできません。タイプは関数シグネチャ全体です。私はint8intを割り当てることができないのと同じ論理だと思います。必要に応じてキャストすることができますが、移動する場合は別々のタイプであり、必要なコンバージョンを割り当てて対応させる必要があります。あなたは何ができるか

は、このような空のインタフェースを返すために、2番目の関数のシグネチャを変更です:

func(interface{}, proto.Message) interface{} 

func reduceMsg(a interface{}, b proto.Message) interface{} { 
    var a []*PersistentData 
    // do something here 
    return a 
} 

この方法は、関数のシグネチャは同じなので、同じタイプを考慮だとあなたは[]*PersistentDataを戻ってきています。もちろん、型アサーションを行う前に型アサーションを行う必要があります。なぜなら、それが関数が返す型であるため、プログラムは{}interfaceとして扱うからです。一般的に

+1

"int8をintに割り当てることができないのは同じロジックだと思う" ---私は同意できない。 'int8'に' int 'を代入することはできません。これは、データが失われる可能性があるからです。しかし、共分散はまったく別の話です。互換性のある型です: '[] string'は' interface {} 'に代入可能です。 Co/contra-varianceのサポートは、単に型の割り当て可能性よりも高いレベルの操作です。 – zerkms

+1

私はそれが別のコンセプトであることを知っています。彼らはそのように言語を設計する動機があるかもしれませんが、それが許されない理由は同じです。それが別のタイプの場合は、割り当てを行うことはできません。関数の型は、関数の署名全体によって定義されます。 https://golang.org/ref/spec#Function_types – Topo

関連する問題