Яка мета атрибуцій типу в Scala?


75

У специфікації немає багато інформації про те, що це за тип атрибуції, і, звичайно, там немає нічого про призначення. Окрім того, щоб "змусити прохідні варарги працювати", для чого б я використовував атрибуцію типу? Нижче наведено шкалу REPL для синтаксису та ефектів його використання.

scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s:Object
p: java.lang.Object = Dave

scala> p.length
<console>:7: error: value length is not a member of java.lang.Object
       p.length
         ^
scala> p.getClass
res10: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> s.getClass
res11: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> p.asInstanceOf[String].length
res9: Int = 4

Відповіді:


81

Атрибуція типу просто повідомляє компілятору, який тип ви очікуєте від виразу з усіх можливих допустимих типів.

Тип є дійсним, якщо він поважає існуючі обмеження, такі як оголошення про дисперсію та тип, і це або один із типів, до якого він застосовує вираз " є ", або існує перетворення, яке застосовується за обсягом.

Отже, java.lang.String extends java.lang.Objectотже, будь- Stringякий також є Object. У своєму прикладі ви заявили, що хочете, щоб вираз sтрактувався як а Object, а не як String. Оскільки немає обмежень, що перешкоджають цьому, і бажаний тип є одним із типів s a , це працює.

Чому б ви цього хотіли? Розглянемо це:

scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s: Object
p: java.lang.Object = Dave

scala> val ss = scala.collection.mutable.Set(s)
ss: scala.collection.mutable.Set[java.lang.String] = Set(Dave)

scala> val ps = scala.collection.mutable.Set(p)
ps: scala.collection.mutable.Set[java.lang.Object] = Set(Dave)

scala> ss += Nil
<console>:7: error: type mismatch;
 found   : scala.collection.immutable.Nil.type (with underlying type object Nil)
 required: java.lang.String
       ss += Nil
             ^

scala> ps += Nil
res3: ps.type = Set(List(), Dave)

Ви також можете виправити це за типом, який приписується sпри ssоголошенні, або ви можете оголосити ssтип Set[AnyRef].

Однак декларації типів досягають того самого, лише доки ви присвоюєте значення ідентифікатору. Що завжди можна зробити, звичайно, якщо він не дбає про засмічення коду одноразовими ідентифікаторами. Наприклад, наступне не компілюється:

def prefixesOf(s: String) = s.foldLeft(Nil) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

Але це робить:

def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

Було б глупо використовувати тут ідентифікатор замість Nil. І хоча я міг би просто писати List[String]()замість цього, це не завжди варіант. Розглянемо це, наприклад:

def firstVowel(s: String) = s.foldLeft(None: Option[Char]) { 
  case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
  case (vowel, _) => vowel
}

Для довідки, ось що має сказати специфікація Scala 2.7 (проект від 15 березня 2009 р.) Про атрибуцію типу:

Expr1 ::= ...
        | PostfixExpr Ascription

Ascription ::= ‘:’ InfixType
             | ‘:’ Annotation {Annotation}
             | ‘:’ ‘_’ ‘*’

28

Одна з можливостей полягає в тому, коли мережевий та послідовний протоколи навантажують речі, тоді це:

val x = 2 : Byte

набагато чистіше, ніж

val x = 2.asInstanceOf[Byte]

Друга форма також є перетворенням середовища виконання (не обробляється компілятором) і може призвести до деяких цікавих умов перевитрати / недотоку.


1
Хе, дізнався щось нове. Я роблю невдалий обсяг роботи з мережевим протоколом. Добре знати!
Justin W

21
Чому б не використовувати повсякденний синтаксис? val x: Byte = 2
Jerry101

0

Я використовую надпис типу для паперу над отворами у висновку типу Scala. Наприклад, foldLeft над колекцією типу A приймає початковий елемент типу B і функцію (B, A) => B, яка використовується для складання елементів колекції в початковий елемент. Фактичне значення типу B виводиться з типу початкового елемента. Оскільки Nil розширює List [Nothing], використання його як початкового елемента викликає проблеми:

scala> val x = List(1,2,3,4)
x: List[Int] = List(1, 2, 3, 4)

scala> x.foldLeft(Nil)( (acc,elem) => elem::acc)
<console>:9: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              x.foldLeft(Nil)( (acc,elem) => elem::acc)
                                                 ^

scala> x.foldLeft(Nil:List[Int])( (acc,elem) => elem::acc )
res2: List[Int] = List(4, 3, 2, 1)

Як варіант, ви можете просто використовувати List.empty [Int] замість Nil: List [Int].

scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc )
res3: List[Int] = List(4, 3, 2, 1)

редагувати: List.empty [A] реалізовано як

override def empty[A]: List[A] = Nil

(джерело)

Це фактично більш багатослівна форма Nil: List [A]


Чому ні x.foldLeft[List[Int]](Nil)( (acc,elem) => elem::acc )?
Джеффрі Агілера,

0

Ви можете виявити, що цей потік висвітлює, якщо він трохи заплутаний. Важливо відзначити, що ви додаєте підказки щодо обмежень до засобу перевірки типу - це дає вам трохи більше контролю над тим, що робить ця фаза компіляції.


:) Я розмістив тут своє запитання, щоб воно було збережене; я вибрав відповідь із тієї
теми,

Вибачте, щойно побачив це. Готово.
Justin W

0

Висновок типу: ми можемо пропустити Явно вказавши Ім'я типу Що-небудь у вихідному коді, що називається Висновок типу. (Хоча це потрібно у деяких виняткових випадках).

Типова атрибуція: Якщо явно говорити про тип чогось, це називається атрибуцією типу. Яку різницю це може зробити?

напр .: val x = 2: байт

також див .: 1. Ми можемо явно надати тип повернення нашим функціям

def t1 : Option[Option[String]] = Some(None)

> t1: Option[Option[String]]

Іншим способом заяви про це може бути:

def t2 = Some(None: Option[String])
> t2: Some[Option[String]]

Тут ми не вказали Option[Option[String]]тип return явно, і Компілятор вивів його як Some[Option[String]]. Чому Some[Option[String]]це тому, що ми використовували атрибуцію типу у визначенні.

  1. Інший спосіб, яким ми можемо використовувати те саме визначення, це:

    def t3 = Some(None)

    > t3: Some[None.type]

Цього разу ми явно нічого не сказали компілятору (ні це дефі). І це вивело наше визначення як Деякі [None.type]

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.