확장 메서드

확장 메서드

타입을 정의하고 나서, 그 타입에 메서드를 추가하고 싶을 때가 있어요. 누군가 이미 만들어 둔 클래스는 함부로 건드릴 수 없잖아요. 그럴 때 쓰는 게 확장 메서드(extension method)예요. Scala 3에서 새로 도입된 기능이라, 기존 Scala 2에서는 비슷한 결과를 implicit class로 만들어냈어요.

출처: Scala 3 Book — Extension Methods

본문

확장 메서드는 타입이 정의된 이후에 그 타입에 메서드를 추가할 수 있게 해줘요. 즉, 이미 닫혀 있는(closed) 클래스에 새 메서드를 더할 수 있게 해주는 기능이에요.

예를 들어, 다른 누군가가 Circle 클래스를 이미 만들어 두었다고 생각해 볼게요.

case class Circle(x: Double, y: Double, radius: Double)

그런데 이제 circumference(원둘레) 메서드가 필요한데, 그 사람의 소스 코드는 수정할 수 없다고 해 볼게요.

프로그래밍 언어에 용어 추론(term inference) 같은 개념이 도입되기 전에는, 별도의 클래스나 객체에 메서드를 작성하는 방법밖에 없었어요. 이렇게요.

object CircleHelpers:
  def circumference(c: Circle): Double = c.radius * math.Pi * 2

그리고 이렇게 호출해서 썼죠.

val aCircle = Circle(2, 3, 5)

// 확장 메서드 없이
CircleHelpers.circumference(aCircle)

하지만 확장 메서드를 쓰면 Circle 인스턴스에 직접 동작하는 circumference 메서드를 만들 수 있어요.

extension (c: Circle)
  def circumference: Double = c.radius * math.Pi * 2

이 코드를 보면 두 가지가 보이죠.

  • Circle은 확장 메서드 circumference가 추가될 타입이에요.
  • c: Circle이라는 문법은 확장 메서드 안에서 변수 c를 참조할 수 있게 해줘요.

그러면 코드에서는 circumference가 원래 Circle 클래스에 정의되어 있던 것처럼 그냥 호출하면 돼요.

aCircle.circumference

확장 메서드 import하기

circumference가 패키지 lib에 정의되어 있다면, 다음과 같이 import해서 쓸 수 있어요.

import lib.circumference

aCircle.circumference

그리고 import를 빼먹었을 때도 컴파일러가 도와줘요. 아래처럼 자세한 컴파일 오류 메시지를 보여주거든요.

value circumference is not a member of Circle, but could be made available as an extension method.

The following import might fix the problem:

   import lib.circumference

확장 메서드 여러 개 정의하기

extension 키워드는 괄호 안에 있는 타입에 확장 메서드를 하나 이상 정의하겠다는 뜻이에요. 한 타입에 여러 확장 메서드를 정의하려면 이런 문법을 써요.

extension (c: Circle)
  def circumference: Double = c.radius * math.Pi * 2
  def diameter: Double = c.radius * 2
  def area: Double = math.Pi * c.radius * c.radius

더 알아보기