Розуміння того, що ключове слово "type" робить у Scala


144

Я новачок у Scala, і я не міг дуже багато знайти про typeключове слово. Я намагаюся зрозуміти, що може означати наступний вираз:

type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

FunctorType це якийсь псевдонім, але що він означає?

Відповіді:


148

Так, псевдонім типу FunctorType - це лише скорочення

(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

Псевдоніми типів часто використовуються для простоти решти коду: тепер ви можете писати

def doSomeThing(f: FunctorType)

що інтерпретується компілятором як

def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)

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

Є також кілька інших випадків цікаво використовувати для type, як описано, наприклад , в цьому розділі про Програмування в Scala .


198

Насправді typeключове слово в Scala може зробити набагато більше, ніж просто зв'язати складний тип на коротше ім’я. Він представляє членів типу .

Як відомо, клас може мати членів поля та членів методу. Що ж, Scala також дозволяє класу мати членів типу.

У вашому конкретному випадку, typeце дійсно, введення псевдоніма, який дозволяє писати більш стислий код. Система типу просто замінює псевдонім фактичним типом, коли виконується перевірка типу.

Але ви також можете мати щось подібне

trait Base {
  type T

  def method: T
}

class Implementation extends Base {
  type T = Int

  def method: T = 42
}

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

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

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

Будь ласка, дивіться цю відмінну відповідь для більш детальної інформації:

Scala: Абстрактні типи проти дженерики


44
Важливо пам'ятати, що використання типу всередині класу створює член типу замість псевдоніму. Тож якщо вам потрібен лише псевдонім типу, визначте його в супутньому об’єкті.
Rüdiger Klaehn

9

Мені сподобалась відповідь від Роланда Евальда, оскільки він описав дуже простий випадок використання псевдоніма типу, а для більш детальної роботи представив дуже приємний підручник. Однак, оскільки інший випадок використання введено в цю посаду з назвою членів типу , я хотів би згадати найбільш практичний випадок використання цього, який мені дуже сподобався: (ця частина взята звідси :)

Тип реферату:

type T

T вище говорить, що цей тип, який буде використовуватися, поки невідомий, і залежно від конкретного підкласу він буде визначений. Найкращий спосіб розуміння понять програмування - це приклад: Припустимо, у вас такий сценарій:

Без абстракції типу

Тут ви отримаєте помилку компіляції, оскільки метод поїдання в класах Корова та Тигр не змінюють метод їжі в класі Animal, оскільки їхні параметри відрізняються. Це Трава в класі Корова, М'ясо в класі Тигр проти Їжа в класі Тварина, який є супер класом, і всі підкласи повинні відповідати.

Повернімося до абстракції типу, на наступній схемі та просто додавши абстракцію типу, ви можете визначити тип введення відповідно до самого підкласу.

З абстрактним типом

Тепер подивіться наступні коди:

  val cow1: Cow = new Cow
  val cow2: Cow = new Cow

  cow1 eat new cow1.SuitableFood
  cow2 eat new cow1.SuitableFood

  val tiger: Tiger = new Tiger
  cow1 eat new tiger.SuitableFood // Compiler error

Компілятор задоволений, і ми вдосконалюємо наш дизайн. Ми можемо годувати свою корову коровою. Підходящий корм та компілятор заважають нам годувати корову їжею, яка підходить для тигра. Але що робити, якщо ми хочемо зробити різницю між типом корови1 підходящої їжі та коровою2 SuitabeFood. Іншим словом, у деяких сценаріях було б дуже зручно, якщо шлях, яким ми доходимо до типу (звичайно через об’єкт), має значення. Завдяки вдосконаленим функціям в масштабі Scala, можливо:

Типи, залежні від шляху: об'єкти Scala можуть мати типи як члени. Значення типу залежить від шляху, яким ви користуєтесь для доступу до нього. Шлях визначається посиланням на об'єкт (він же екземпляр класу). Для реалізації цього сценарію потрібно визначити клас Трава всередині Корови, тобто Корова - це зовнішній клас, а Трава - внутрішній клас. Структура буде такою:

  class Cow extends Animal {
    class Grass extends Food
    type SuitableFood = Grass
    override def eat(food: this.SuitableFood): Unit = {}
  }

  class Tiger extends Animal {
    class Meat extends Food
    type SuitableFood = Meat
    override def eat(food: this.SuitableFood): Unit = {}
  }

Тепер, якщо ви спробуєте скласти цей код:

  1. val cow1: Cow = new Cow
  2. val cow2: Cow = new Cow

  3. cow1 eat new cow1.SuitableFood
  4. cow2 eat new cow1.SuitableFood // compilation error

У рядку 4 ви побачите помилку, оскільки Трава зараз є внутрішнім класом Корова, тому для створення екземпляра Трави нам потрібен коров’ячий об’єкт, і цей корівний об’єкт визначає шлях. Таким чином, 2 коров’ячих об'єкта породжують 2 різних шляху. У цьому випадку корова2 хоче лише їсти спеціально створену для неї їжу. Так:

cow2 eat new cow2.SuitableFood

Тепер всі раді :-)


5

Просто приклад, щоб дізнатися, як використовувати "type" як псевдонім:

type Action = () => Unit

Вищенаведене визначення визначає Дію як псевдонім типу процедур (методів), які приймають порожній список параметрів і повертають Одиницю.

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