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