2016-06-25 8 views
4

私はこのように私のparse機能で使用するための一般的な代数的データ型を定義したい:Tはその後、未定義の参照であるようなぜ汎用代数データ型はメンバ型に `T`を必要としますか?

sealed class Result<T> { 
    class Success(val value: T, val pos: Int) : Result<T>() 
    class Failure(val message: String, val pos: Int) : Result<T>() 
} 

fun <T> parse(t: Parser<T>, input: String, initialPos: Int = 0, collectErrors: Boolean = true) : Result<T> { 

しかし、これは許可されていません。

私はそれが動作すべてのメンバー・タイプにTを追加する場合:

sealed class Result<T> { 
    class Success<T>(val value: T, val pos: Int) : Result<T>() 
    class Failure<T>(val message: String, val pos: Int) : Result<T>() 
} 

私にはこれは私が、私はここで何かが欠けています信じていますこれはやや混乱しています。最初のケースでメンバータイプを定義するときにTが表示されないのはなぜですか?

Successのインスタンスを作成するときに、私は構文があることを期待するほか

Result<T>.Success<T>(tv.someValue, pos) 

しかし、それが代わりに動作しません、私はこれを実行します。

Result.Success<T>(tv.someValue, pos) 

これが望ましい構文ですが私にはなぜ結果をTに残すべきかを理解するのに苦労しています。

答えて

6

ResultがTという名前の単一の汎用パラメータを使用して、一般的なクラスでありますただし、クラス名はですが、Result<T>ではありません。

Successも汎用クラスです。したがって、汎用的なので、Success<T>と定義する必要があります。あなたがしなければ、それはもはや一般的ではありません。 Resultの汎用クラスであるサブクラスであっても、非ジェネリック型である可能性があります。たとえば、

class Success(val value: String, val pos: Int) : Result<String>() 

結果と失敗は一般的なものですが、何にも使用されません。だから、あなたが実際に今

sealed class Result { 
    class Success<T>(val value: T, val pos: Int) : Result() 
    class Failure(val message: String, val pos: Int) : Result() 
} 

としてあなたのクラスを定義することができ、なぜあなたは Result.Success<T>(tv.someValue, pos)なく Result<T>.Success<T>(tv.someValue, pos)を使用する必要がありますか?

クラス名はResult.Successです。パラメータ型はクラス名の一部ではありません。

val r = Result.Success("foo", 1) 

Success<String>のインスタンスを作成します。それが推測されますので、時間のほとんどは、それがすべてで、それを指定する必要はありません。あなたの代わりにSuccess<CharSequence>を作成したい場合は、明示的にジェネリック型を指定する必要があります:あなたの例では

val r = Result.Success<CharSequence>("foo", 1) 

または

val r: Result.Success<CharSequence> = Result.Success("foo", 1) 
+1

ありがとうございます。 'Result'は厳密には一般的である必要はありませんが、' parse'は 'Success 'ジェネリック型が 'Parser 'と同じである 'Result'を生成するので、好きです。私がResult Iに 'T 'を含まない(おそらく誤って)とすれば、APIはタイプセーフではないと信じています。 – FuleSnabel

+0

'fun foo():Result 'のようなメソッドシグネチャが必要な場合はどうすればいいですか?返される値はSuccess またはFailureのいずれかになります。 – miguel

4

ルールはJavaと同じです。基本的には、Resultの静的ネストクラスであるSuccessFailureになります。 Kotlinには「メンバ型」はありません。静的なネストされたクラスは、外部クラスのスコープにアクセスできる通常のクラスです。また、クラスが汎用スーパークラスを継承している場合は、汎用タイプのパラメータを常にバインドする必要があります。

対照的に、静的でないネストされたクラス(innerキーワードで示される)は、常に外部クラスのジェネリック型パレメーターを保持します。

open class Foo<T> { 
    inner class Bar : Foo<T>() 
} 

をあなたはFooのインスタンスを持っている必要がありますBarをインスタンス化するには:あなたは次のタイプの階層を構築することができますこの方法

val b = Foo<String>().Bar() 
+0

おかげで動作するはずです。 'T'がスコープの一部であると思うので、' T'が静的内部クラスに見えない理由は、やはり幾分困惑しています。 – FuleSnabel

+0

私はそれがJavaでどのように動作し、Kotlinでも同じように動作すると思います。別のところで動作する言語から来ていますか? –

+1

@FuleSnabel静的なネストされたクラス(静的な内部クラスのようなものはありません)は、トップレベルのクラスと同じです。唯一の違いは、名前がより奇妙で(SuccessではなくResult.Success)、囲むクラスのプライベートメンバーにアクセスできることです(逆もまた同様です)。それ以外は、トップレベルのクラスに似ています。内部クラスは、所有者**インスタンス**への暗黙の参照を持つため、異なるクラスです。 –

0

を三つの異なる汎用パラメータではなく、1があります。私。あなたのコードは同等です:

sealed class Result<I> { 
    class Success<A>(val value: A, val pos: Int) : Result<A>() 
    class Failure<B>(val message: String, val pos: Int) : Result<B>() 
} 

しかし、どのように他の回答に言及、あなたはIBパラメータを使用していないので、それらは省略されるように優れています。

+0

プロパティ 'value'の型は 'T'です。あなたのコードはコンパイルされません。 –

+0

@KirillRakhmanありがとう! – voddan

0

あなたはこのようなアウト分散を使用する場合は、

sealed class Result<out T> { 
    data class Success<out T>(val value: T, val pos: Int) : Result<T>() 
    data class Failure(val message: String, val pos: Int) : Result<Nothing>() 
} 
関連する問題