簡體   English   中英

Scala泛型混亂

[英]Scala generics Confusion

我有一些通用/ OOP Scala代碼(沒用,只是課堂練習)

我有一個Container接口,“IterableContainer”,它接收並返回其類型是AnyRef的子類的對象。 它有一個具體的子類,它也接受並返回其類型是AnyRef的子類的對象。

  trait IterableContainer[Type <: AnyRef] {

    def length: Int

    def getAt(index: Int): Type

    def append(element: Type)
  }

  class IterableArrayList[T <: AnyRef]() extends IterableContainer[T] {

    val underlyingContainer = new ArrayBuffer[T](16)

    override def length: Int = {
      return underlyingContainer.length
    }

    override def getAt(index: Int): T =
    {
      if (index < underlyingContainer.length) {
        return underlyingContainer(index)
      } else {
        return null // Expression of type T does not conform to expected type. 
      }
    }

    override def append(element: T) = {
      underlyingContainer :+ element // :+ means append
    }
  }

任何人都可以解釋為什么當顯式地將T聲明為擴展AnyRef的類型的對象時,我不能返回null?

另外,如果你比我更了解Scala的泛型,請進一步解釋 - 它們對我來說毫無意義(相對於C ++泛型)。

問題是T <: AnyRef並不意味着T >: Null

我相信唯一的反例是Nothing

IterableArrayList的類型參數上添加額外的(較低)類型綁定會使編譯器滿意:

class IterableArrayList[T >: Null <: AnyRef]() extends IterableContainer[T] {

現在,編譯器知道T是一個亞型AnyRef 的超Null


現在,您可能會想到自己, “這不會導致在Scala中編寫庫代碼的各種問題嗎?人們必須要添加T >: Null無處不在!”

然而,答案是否定的。

為什么? 因為Scala程序員幾乎從不使用null

我們以List為例。 獲取列表的第一個元素有兩種方法:

def head: A (scaladoc)

def headOption: Option[A] (scaladoc)

如果您在空列表上調用head ,則會出現異常。 如果在空列表上調用headOption ,則會得到None

這是Scala庫的常用策略:要么拋出異常,要么返回Option類型 - 永遠不會返回null

使用Option[T]示例:

override def getAt(index: Int): Option[T] =
  if (index < underlyingContainer.length) {
    Some(underlyingContainer(index))
  } else {
    None
  }

使用例外的示例:

override def getAt(index: Int): T = underlyingContainer(index)

請注意,如果索引無效,則基礎ArrayBuffer已拋出IndexOutOfBoundsException 如果用戶傳入負索引,這還具有正常工作的附加優勢...(如果使用Option可能需要為條件添加0 <= index 。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM