为什么通用代数数据类型在成员类型上需要`T`?

时间:2016-06-25 14:13:20

标签: generics kotlin

我想定义一个通用代数数据类型,用于我的[ [ task_1, task_2, task_3 ], [ task_4, task_5 ] ] 函数,如下所示:

renderTasks() {
  let filteredTasks = this.props.tasks;
  let taskRows = filteredTasks.reduce(function (rows, task, i) {
    let rowIndex = Math.floor(i / 3);

    if (i % 3 == 0) {
      rows[rowIndex] = [task]
    } else {
      rows[rowIndex].push(task)
    }
    return rows;
  }, []);

  return taskRows.map(this.renderTasksRow);
}

renderTasksRow(rowTasks) {
  return <Row>{rowTasks.map(this.renderTask)}</Row>;
}

renderTask(task) {
  const currentUserId = this.props.currentUser && this.props.currentUser._id;
  const showPrivateButton = task.owner === currentUserId;

  return (
    <Task
      key={task._id}
      task={task}
      showPrivateButton={showPrivateButton}
    />
  );
}

然而,这是不允许的,因为parse是未定义的引用。

如果我将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

对我而言,这有点令人困惑,这让我相信我在这里错过了一些东西。在第一种情况下定义成员类型时,为什么没有看到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)

4 个答案:

答案 0 :(得分:6)

Result是一个泛型类,有一个名为T的通用参数。但是,类名称为Result,而不是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 :(得分:4)

规则与Java中的规则相同。它基本上归结为SuccessFailureResult的静态嵌套类。没有&#34;成员类型&#34;在Kotlin中,静态嵌套类是可以访问外部类范围的常规类。如果一个类扩展了泛型超类,它总是需要绑定泛型类型参数。

相反,非静态嵌套类(由inner关键字表示)始终带有外部类的泛型类型参数。这样,您可以构造以下类型层次结构:

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

要实例化Bar,您需要拥有Foo的实例:

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

答案 2 :(得分:1)

如果你使用像这样的out方差

,它应该有效
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>()
}

答案 3 :(得分:0)

在您的示例中,有三个不同的通用参数,而不是一个。即你的代码相当于:

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参数,因此最好省略它们。