IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  Технология Java  >

Путеводитель по Scala для Java-разработчиков: Наследование функциональности

Наследование в Scala: объекты и функции

developerWorks
Опции документа
PDF format - Fits A4 and Letter

PDF - Fits A4 and Letter
48 КБ

Загрузить Adobe® Reader®

Опции документа, требующие включения JavaScript, не отображаются

Обсудить


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Тед Ньювард, Глава, Neward & Associates

08.07.2009

Scala поддерживает все возможности наследования функциональности, предусмотренные в Java™, но при этом сам механизм наследования может показаться несколько необычным. В этой статье Тед Ньюард расскажет о полиморфизме в стиле Scala, сочетающем объектно-ориентированные и функциональные черты, но при этом сохраняющем прекрасную совместимость с моделью наследования, принятой в Java.

В течение последних 20 лет (по крайней мере, лучшей их части) центральным звеном объектно-ориентированного дизайна было понятие наследования. Языки программирования, не поддерживающие наследования, например Visual Basic, всячески высмеивались и признавались негодными для серьезных проектов. В то же время остальные языки реализуют механизм наследования настолько по-разному, что это зачастую становилось причиной продолжительных дебатов. Предметом одного из таких споров было множественное наследование. Одни, например создатели С++, считали его необходимым, в то время как другие, в частности создатели С# и Java, были убеждены в его неоправданности. Недавно появились такие языки как Ruby и Scala, которые занимают промежуточное положение по этому вопросу. Частично эти моменты обсуждались в предыдущей статье при рассмотрении признаков (traits) в Scala (см. Ресурсы).

Об этой серии

Тед Ньювард погружается в язык программирования Scala и берет вас с собой. В этой новой серии developerWorks вы узнаете вокруг чего поднята такая шумиха и увидите некоторые лингвистические возможности Scala в действии. Код Scala и код Java будут показаны бок о бок, если таковое сравнение будет важно, но (как скоро выяснится) многие вещи в Scala не могут быть напрямую соотнесены с чем-либо таким, что вам знакомо из Java-программирования, но в этом и заключается основное очарование Scala! В конце концов, если Java-код способен это сделать, зачем же утруждать себя изучением Scala?

Как и все популярные языки программирования, Scala предоставляет механизм для наследования реализации (см. Ресурсы). В Java используется модель одиночного наследования, которая позволяет расширять базовые классы, добавляя в наследниках новые методы и поля. Несмотря на определенные синтаксические отличия, наследование в Scala во многом повторяет принципы, заложенные в Java. Основные различия заключаются в том, что наследование в Scala сочетает в себе черты объектно-ориентированного и функционального стиля программирования. Именно это является темой настоящей статьи.

Простые объекты в Scala

Как и в предыдущих статьях, для изучения механизма наследования в Scala будет использоваться класс Person. Код класса приведен в листинге 1.


Листинг 1. Привет, я - экземпляр класса Person
        
// Это Scala
class Person(val firstName:String, val lastName:String, val age:Int)
{
  def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                         " age="+age+"]"
}

Person представляет собой пример простого класса Scala (plain old scala object), содержащего поля, доступные для чтения. Как вы помните, для того чтобы добавить возможность изменения свойств, достаточно поменять ключевые слова val на var в объявлении главного конструктора класса.

Использование класса Person также не таит в себе никаких подводных камней (листинг 2).


Листинг 2. PersonApp
        
// Это Scala
object PersonApp
{
  def main(args : Array[String]) : Unit =
  {
    val bindi = new Person("Tabinda", "Khan", 38)
    System.out.println(bindi)
  }
}

Пока это не более чем базовый пример использования классов Scala – в нем нет ничего особенного увлекательного.



В начало


Абстрактные методы в Scala

Вскоре становится очевидно, что класс Person не предоставляет никаких средств для выражения одного из главных аспектов, характеризующих людей – их деятельности. Большинство людей склоняются к тому, что человек предназначен для чего-то большего, чем просто существование в виде объекта, занимающего некоторую область в пространстве. Поэтому имеет смысл добавить в класс Person метод, служащий для наполнения жизни объекта смыслом (листинг 3).


Листинг 3. Пора заняться делом
        
// Это Scala
class Person(val firstName:String, val lastName:String, val age:Int)
{
  override def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                          " age="+age+"]"

  def doSomething = // хм... а что делать-то?
}

Сразу же возникает вопрос: а что собственно делают люди? Некоторые рисуют, другие поют, третьи программируют, четвертые играют в видео-игры, а кто-то и вовсе бездельничает (если не верите – спросите кого-нибудь из тинэйджеров). Поэтому имеет смысл создать классы-наследники Person вместо того, чтобы пытаться реализовать все эти действия в самом классе Person. Пример наследника приведен в листинге 4.


Листинг 4. Этот объект не сильно занят
        
// Это Scala
class Person(val firstName:String, val lastName:String, val age:Int)
{
  override def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                          " age="+age+"]"

  def doSomething = // хм... а что делать-то?
}

class Student(firstName:String, lastName:String, age:Int)
  extends Person(firstName, lastName, age)
{
  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
}

Однако при компилировании этого кода возникает ошибка, обусловленная тем, что метод Person.doSomething не закончен. Он должен быть либо реализован (в этом случае логично генерировать исключения, говорящие о необходимости перегрузки метода в классе-наследнике), либо объявлен как абстрактный, т. е. метод без кода, подобному абстрактным методам в Java. Мы выберем второй вариант (листинг 5).


Листинг 5. Абстрактный класс Person
        
// Это Scala
abstract class Person(val firstName:String, val lastName:String, val age:Int)
{
  override def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                          " age="+age+"]"

  def doSomething; // Обратите внимание на точку с запятой
                   // Она необязательна, но я лично предпочитаю
                   // ее ставить по стилистическим соображениям
}

class Student(firstName:String, lastName:String, age:Int)
  extends Person(firstName, lastName, age)
{
  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
}

Ключевое слово abstract явно указывает компилятору на то, что этот класс является абстрактным. Поведение компилятора при этом аналогично компилятору Java.

Появление функций

Благодаря тому, что Scala сочетает в себе объектный и функциональный подходы к программированию, функциональность Person можно выразить без создания классов-наследников. Пример может выглядеть немного непривычно, но он подчеркивает характерные особенности совмещения разных стилей в Java, а также иллюстрирует интересные идеи, которые из этого произрастают.

Как вы помните из предыдущих статей, в Scala функции рассматриваются аналогично обычным значениям, например значениям базовых типов Int, Float и Double. Это свойство языка можно использовать при моделировании типа Person, указав, что doSomething является не перегружаемым методом, а функциональным значением (function value), которое может быть вызвано, заменено, либо расширено. Пример подобного подхода показан в листинге 6.


Листинг 6. Работяга
        
// Это Scala    
class Person(val firstName:String, val lastName:String, val age:Int)
{
  var doSomething : (Person) => Unit = 
    (p:Person) => System.out.println("Я - " + p + " и мне пока нечем заняться!");
    
  def work() =
    doSomething(this)
    
  override def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                          " age="+age+"]"
}

object App
{
  def main(args : Array[String]) =
  {
    val bindi = new Person("Tabinda", "Khan", 38)
    System.out.println(bindi)
    
    bindi.work()
    
    bindi.doSomething =
      (p:Person) => System.out.println("Я редактирую учебники")
      
    bindi.work()
    
    bindi.doSomething =
      (p:Person) => System.out.println("Я читаю HTML-книги")
      
    bindi.work()
  }
}

Использование функций в качестве базовых средств проектирования приложения широко применяется в динамических языках, в частности, Ruby, Groovy, ECMAScript (более известном под именем JavaScript), а также во многих функциональных языках. Подобное возможно и в других языках, например в C++ для этого есть указатели на функции и на члены классов, а в Java – реализации интерфейсов через анонимные внутренние классы. Однако, как правило, это требует значительно больше усилий, чем в Scala (а также, в Ruby, Groovy и ECMAScript). Во многом это определяется тем, что последние поддерживают расширения понятия "функций высшего порядка", хорошо известного в контексте функционального программирования (ссылки на источники дополнительной информации по функциям высшего порядка приведены в разделе Ресурсы).

Эквивалентность функций и значений в Scala позволяет использовать функции везде, где может потребоваться изменение функциональности на этапе выполнения приложения. Это подход имеет много общего с паттерном Роль – вариацией паттерна проектирования, рассмотренного в знаменитой книге Банды Четырех (Gang of Four). В соответствии с этим принципом роли объектов, такие как статус занятости экземпляра Person, следует представлять в виде динамически изменяемых значений, а не фиксировать статически в иерархии типов.



В начало


Доступ к конструктору базового класса

Те из вас, кто имеет опыт программирования на Java, наверняка помнят, что иногда приходится передавать параметры из конструктора класса-наследника конструктору базового класса, чтобы он мог завершить инициализацию экземпляра. В Scala основной конструктор являются частью объявления класса, а не просто рядовым членом, поэтому передача параметров базовому конструктору выполняется совершенно иначе.

Параметры основного конструктора в Scala описываются непосредственно в объявлении class. При этом можно также использовать ключевое слово val для создания методов чтения (аксессоров), а var – для методов модификации параметров.

Декомпилировав класс Person из листинга 5 при помощи javap, можно увидеть, как он преобразуется в класс Java (листинг 7).


Листинг 7. Результат декомпиляции класса Person
        
// Результат работы javap
C:\Projects\scala-inheritance\code>javap -classpath classes Person
Compiled from "person.scala"
public abstract class Person extends java.lang.Object implements scala.ScalaObje
ct{
    public Person(java.lang.String, java.lang.String, int);
    public java.lang.String toString();
    public abstract void doSomething();
    public int age();
    public java.lang.String lastName();
    public java.lang.String firstName();
    public int $tag();
}    

Основные правила, по которым работает JVM, по-прежнему остаются в силе: классы-наследники Person все так же передают параметры конструктору базового класса, вне зависимости от синтаксиса языка (бывают исключения, но для большинства языков это верно, так как JVM не нравится, когда языки не следуют данному правилу). Разумеется, Scala удовлетворяет этому принципу, так как, с точки зрения Scala, важна полная совместимость с JVM и базовыми классами, написанными на Java. Таким образом, в Scala необходимы синтаксические конструкции, при помощи которых можно было бы вызывать конструктор базового класса из наследников. В то же время они не должны идти вразрез с возможностями добавления методов доступа и модификации полей базового класса.

В качестве конкретного примера рассмотрим класс Student из листинга 5, изменив его, как показано в листинге 8.


Листинг 8. Плохой студент!
        
// Это Scala
// Этот класс не скомпилируется
class Student(val firstName:String, val lastName:String, val age:Int)
  extends Person(firstName, lastName, age)
{
  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
}

Разумеется, компилятору это совсем не понравится, так как мы добавили в класс Student множество методов (firstName, lastName и age), которые конфликтуют с одноименными методами в базовом классе Person. При этом компилятор не знает, пытаемся ли мы перегрузить методы базового класса или добавить новые (в любом случае это было бы неудачным решением, так как новые методы были бы скрыты за старыми). Вскоре будет показано, как можно перегружать базовые методы, но в данном примере нас интересует нечто другое.

Необходимо отметить, что в Scala параметры конструктора класса Person отнюдь не обязаны в точности соответствовать параметрам конструктора Student (в примерах это сделано исключительно в целях упрощения). Соответствие параметров регулируется теми же правилами, что и в Java. Кроме того, как и в Java, конструктору класса-наследника могут потребоваться дополнительные параметры (листинг 9).


Листинг 9. Требовательный студент!
        
// Это Scala
class Student(firstName:String, lastName:String, age:Int, val subject:String)
  extends Person(firstName, lastName, age)
{
  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
}

Как и в предыдущих примерах, в глаза бросается сходство Scala и Java, по крайней мере в том, что касается наследования и отношений между классами.



В начало


Синтаксические различия

Вполне возможно, что вы уже раздумываете над тонкими моментами в синтаксисе Scala, например, над тем, что в Scala нет таких различий между полями и методами, как в Java. На самом деле, Scala осознанно проектировался таким образом, чтобы разработчики могли скрывать разницу между полями и методами от компонентов, обращающихся к базовому классу. Обратите внимание на пример в листинге 10.


Листинг 10. Кто я?
        
// Это Scala
abstract class Person(val firstName:String, val lastName:String, val age:Int)
{
  def doSomething
  
  def weight : Int
    
  override def toString = "[Person: firstName="+firstName+" lastName="+lastName+
                          " age="+age+"]"
}

class Student(firstName:String, lastName:String, age:Int, val subject:String)
  extends Person(firstName, lastName, age)
{
  def weight : Int =
    age // студенты очень тощие

  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
}

class Employee(firstName:String, lastName:String, age:Int)
  extends Person(firstName, lastName, age)
{
  val weight : Int = age * 4 // Сотрудники весьма упитанные!

  def doSomething =
  {
    System.out.println("Я очень занят, дорогая, клянусь! (ребята, передайте пива!)")
  }
}

В данном примере weight – это метод без параметров, всегда возвращающий значение типа Int. Поскольку он выглядит очень похоже на методы, реализующие свойства в Java, то в Scala его можно определять двумя способами: как метод (см. класс Student), либо как поле с аксессором (см. класс Employee). Благодаря этой синтаксической особенности языка обеспечивается определенная гибкость при реализации наследников абстрактного класса. В Java подобная гибкость возможна только при условии, что доступ к каждому полю осуществляется через его get- и set-методы. Плохо это или хорошо, но немногие Java-разработчики следуют этому принципу, поэтому данная возможность используется нечасто. Кроме того, в Scala это подход также работает для скрытых/приватных членов класса.



В начало


От @Override к override

Очень часто в классе-наследнике требуется изменить поведение метода, определенного в базовом классе. В Java для этого достаточно добавить метод с тем же именем и сигнатурой. У этого подхода есть один недостаток: в случае опечатки или определенной неоднозначности в сигнатуре метода код по-прежнему будет компилироваться, однако его поведение будет некорректным.

Для решения этой проблемы в Java 5 используется аннотация @Override. Встретив эту аннотацию, компилятор проверяет, что метод, определенный в классе-наследнике, на самом деле перегружает метод базового класса. В Scala ключевое слово override является обязательной частью синтаксиса, так что его отсутствие приведет к ошибке на этапе компиляции. Например, унаследованный метод toString() должен выглядеть, как показано в листинге 11.


Листинг 11. Пример унаследованного метода
        
// Это Scala
class Student(firstName:String, lastName:String, age:Int, val subject:String)
  extends Person(firstName, lastName, age)
{
  def weight : Int =
    age // Все студенты тощие

  def doSomething =
  {
    System.out.println("Я усердно занимаюсь, мам, клянусь! (ребята, передайте пива!)")
  }
  
  override def toString = "[Student: firstName="+firstName+
                          " lastName="+lastName+" age="+age+
                          " subject="+subject+"]"
}

Как видите, все достаточно очевидно.



В начало


Ключевое слово final

От первого лица: Тед Ньювард о Scala

Из Web-трансляции от JavaWorld вы узнаете о различиях между функциональными и объектно-ориентированными языками, а также о важных областях применения, в которых Java и другие объектно-ориентированные языки недостаточно эффективны.

Иногда требуется не только разрешать перегрузку методов, но и запрещать ее. В некоторых случаях базовый класс не должен позволять изменять поведение его методов в наследниках, либо вообще не позволять создавать наследников. В Java для этого предусмотрено ключевое слово final. Если добавить его к объявлению метода, то он не сможет быть перегружен в дочерних классах. Если пометить класс как final, то он не сможет иметь наследников. В Scala все реализовано точно так же: методы, помеченные как final, не могут быть перегружены, а final-классы не могут иметь дочерних классов.

Следует помнить, что все, что было сказано выше о модификаторах abstract, final и override, относится в равной степени как к обычным методам, так и к методам с "забавными именами" (тем, которые программисты Java, C++ или C# назвали бы операторами). Таким образом, имеет смысл создать базовый класс или признак, определяющий некоторую математическую функциональность. Этот класс (назовем его, например, Mathable) будет определять четыре абстрактных функции "+", "-", "*" и "/", а также другие необходимые операции, такие как pow или abs. После этого другие разработчики могут создавать дополнительные типы, например, класс Matrix, реализуя или расширяя тип Mathable. Эти дочерние типы могут перегружать данные математические методы и внешне выглядеть так же, как типы данных, для которых арифметические операции поддерживаются непосредственно на уровне языка.



В начало


В чем же различие?

Если Scala поддерживает такой высокий уровень совместимости с моделью наследования в Java, как было показано в примерах выше, то должна также поддерживаться возможность наследования Scala-классов от Java-классов и наоборот. На самом деле это совершенно необходимо, так как объекты в Scala (как и в любом языке, компилирующемся в байт-код JVM) должны быть наследниками java.lang.Object. Разумеется, поскольку классы в Scala могут быть наследниками не только классов, а еще, например, признаков, то сам механизм наследования и генерации байт-кода может быть реализован по-другому. Тем не менее, так или иначе, должна быть возможность расширять Java-классы в Scala. Как вы помните, признаки в Scala являются некоторой разновидностью интерфейсов, обладающих функциональностью, поэтому при трансляции компилятор разделяет каждый признак на интерфейс и реализацию методов, которая помещается в классы-наследники признака.

На самом деле, иерархия типов в Scala несколько отличается от иерархии Java. Формально базовым типом, который расширяет все классы Scala, в том числе численные типы, такие как Int, Float и Double, является класс scala.Any. Он содержит базовые методы, поддерживаемые всеми типами в Scala - ==, !=, equals, hashCode, toString, isInstanceOf и asInstanceOf (большинство их названий говорит само за себя). Все остальные классы делятся на две категории: "примитивные" типы являются наследниками scala.AnyVal, а "объектные" типы - scala.AnyRef (наследником последнего является scala.ScalaObject).

Обычно разработчикам не приходится задумываться об этих различиях, однако иногда они могут быть причиной интересных эффектов, которые можно наблюдать, наследуя классы одного языка от классов другого. Обратите внимание на класс ScalaJavaPerson в листинге 12...


Листинг 12. Пример межъязыкового наследования
        // Это Scala
class ScalaJavaPerson(firstName:String, lastName:String, age:Int)
  extends JavaPerson(firstName, lastName, age)
{
  val weight : Int = age * 2 // Кто-нибудь знает, сколько весят люди,
                             // знающие Scala и Java?

  override def toString = "[SJPerson: firstName="+firstName+
                          " lastName="+lastName+" age="+age+"]"
}

... который является наследником класса JavaPerson (листинг 13).


Листинг 13. Этот класс выглядит знакомо, не так ли?
        // Это Java
public class JavaPerson
{
    public JavaPerson(String firstName, String lastName, int age)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    
    public String getFirstName()
    {
        return this.firstName;
    }
    public void setFirstName(String value)
    {
        this.firstName = value;
    }
    
    public String getLastName()
    {
        return this.lastName;
    }
    public void setLastName(String value)
    {
        this.lastName = value;
    }
    
    public int getAge()
    {
        return this.age;
    }
    public void setAge(int value)
    {
        this.age = value;
    }
    
    public String toString()
    {
        return "[Person: firstName" + firstName + " lastName:" + lastName +
            " age:" + age + " ]";
    }
    
    private String firstName;
    private String lastName;
    private int age;
}

При компиляции ScalaJavaPerson будет, как и следовало ожидать, расширять JavaPerson, наследуя все его методы, но вдобавок к этому, в соответствии со спецификацией Scala, он будет также реализовывать интерфейс ScalaObject. Обратите внимание, что поскольку ScalaJavaPerson является классом Scala, он может быть присвоен в качестве значения любой переменной типа Any (листинг 14).


Листинг 14. Использование ScalaJavaPerson
        // Это Scala    
    val richard = new ScalaJavaPerson("Richard", "Campbell", 45)
    System.out.println(richard)
    val host : Any = richard
    System.out.println(host)

Возникает вопрос: а что произойдет, если инстанциировать JavaPerson в Scala и также попробовать присвоить данный экземпляр переменной типа Any? (листинг 15).


Листинг 15. Использование JavaPerson
        
// Это Scala    
    val carl = new JavaPerson("Carl", "Franklin", 35)
    System.out.println(carl)
    val host2 : Any = carl
    System.out.println(host2)

При этом не возникает ошибок ни при компиляции, ни на этапе выполнения благодаря совместимости между типом Any в Scala и java.lang.Object в Java (другими словами, экземпляр JavaPerson ведет себя так, как от него ожидают). С некоторыми оговорками можно сказать, что объект любого типа, расширяющего java.lang.Object, может быть присвоен переменной типа Any (мне говорили о некоторых особых случаях, но я лично с ними никогда не сталкивался).

Итак, что же получается в "сухом остатке"? Во всех встречающихся на практике ситуациях можно без опаски создавать классы Scala, наследующие классы Java, и наоборот. Правда при этом большой проблемой будет придумать, как перегрузить в Java методы с "забавными именами", наподобие "^=!#", определенные в Scala.



В начало


Заключение

Как видите, одним из следствий тесной связи между Scala и Java является то, что модель наследования в Scala оказывается легко доступной для Java-разработчиков. Ключевые моменты, такие как перегрузка методов, видимость членов класса и т. д., работают точно так же. Из всех возможностей Scala наследование, вероятно, выглядит наиболее схоже с Java. Единственное, что выглядит необычно – это синтаксис Scala, который заметно отличается от Java.

Осознав сходства и различия в моделях наследования обоих языков, вы сможете легко создавать Scala-версии Java-приложений. Например, можно реализовать на Scala такие популярные Java-библиотеки и инфраструктуры как JUnit, Servlets, Swing и SWT. Кстати, команда разработчиков Scala уже создала Swing-приложение под названием OOPScala (см. Ресурсы), которое реализует функциональность электронных таблиц при помощи JTable. При этом оно умещается в смехотворное число строк кода – на порядок меньшее, чем потребовалось бы для создания аналога на Java.

Таким образом, если вас интересовало, как можно задействовать Scala в ваших программных продуктах, то теперь вы можете сделать первые реальные шаги к этой цели. Например, рассмотрите возможности создания некоторых компонентов вашего следующего приложения на Scala. Как видите, у вас не должно возникать проблем с наследованием от Java-классов и перегрузкой методов, так как в Scala выполняются те же принципы, что и в Java.



Ресурсы

Научиться
  • Оригинал статьи: The busy Java developer's guide to Scala: Implementation inheritance (Ted Neward, developerWorks, май 2008 г.). (EN)

  • Слушайте Web-трансляцию Scala revealed (JavaWorld, июнь 2008 г.), в которой авторы developerWorks Эндрю Гловер (Andrew Glover) и Тед Ньюард обсуждают различия между объектно-ориентированными и функциональными языками программирования, а также приводят примеры задач, например, связанных с параллельной обработкой или работой с базами данных, для которых Java и другие "чистые" ОО-языки не являются наилучшим выбором. (EN)

  • Прочитайте всю серию Путеводитель по Scala для Java-разработчиков (Тед Ньювард, developerWorks, 2008 г.). (EN)

  • Прочитайте статью "Scala для беженцев из мира Java, часть 5: Признаки и типы" (Дэниел Спивак, Daniel Spiewak, Code Commit, февраль 2008 г.) – еще одно обсуждение модели наследования в Scala. (EN)

  • Ознакомьтесь со статьей "Размышления на тему реализации наследования при помощи примесей" (Дебасиш Гош, Debasish Ghosh, Ruminations of a Programmer, февраль 2008 г.), в которой обсуждаются компромиссы, определяющие модель наследования в Java в настоящее время. (EN)

  • Прочитайте статью "Путеводитель по Scala: функции высшего порядка" (Scala-lang.org), в которой приводится краткий пример использования функций высшего порядка в Scala. (EN)

  • OOPScala: Swing-application, написанное на Scala. (EN)

  • Прочитайте статью "Функциональное программирование на Java" (Абхиджит Белапуркар, Abhijit Belapurkar, developerWorks, июль 2004 г.), в которой обсуждаются преимущества и возможности применения функционального программирования с точки зрения разработчика Java. (EN)

  • Ознакомьтесь со статьей "Scala в примерах" (Мартин Одерски, Martin Odersky, декабрь 2007 г.), в которой приводится краткое введение в Scala, изобилующее примерами. В том числе в ней описывается приложение Quicksort, также использующееся в нашей серии (формат PDF). (EN)

  • Прочитайте Программирование на Scala (Мартин Одерски, Лекс Спун, Lex Spoon и Билл Веннерс; сигнальный экземпляр опубликован Artima в феврале 2008 г.) – первое подробное введение в Scala, написанное в соавторстве с Биллом Веннерсом. (EN)

  • Сотни статей по всем аспектам программирования на Java можно найти на сайте developerWorks, в разделе Технология Java.


Получить продукты и технологии
  • Загрузите Scala. На настоящий момент последней является версия 2.7.0-final. (EN)


Обсудить


Об авторе

Тед Ньювард - глава Neward & Associates, где он консультирует, руководит, обучает и внедряет Java, .NET, XML Services и другие платформы. Он проживает возле Сиэтла, штат Вашингтон.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



 


 


 


Поделиться этой статьей:

забобрить забобрить memori сохранить в memori




В начало


IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.
    IBM в России Конфиденциальность Контакты