2010-11-17 19 views
5

Trong C++ tôi có thể làm như sau:Có thể mã hóa các kiểu trả về chung trong Scala tương tự như các mẫu C++?

template<typename T, typename V> 
struct{ 
    void operator()(T _1, V _2){ 
     _2.foo(_1); 
    } 
}; 

cho phép tôi tùy tiện quyết định sử dụng bất kỳ đối tượng trong đó có một số phương pháp được gọi là "foo" mà sẽ đưa một số loại "T" mà không chỉ định trước hoặc là kiểu lập luận của hàm "foo" cũng như kiểu trả về của hàm đã nói.

Khi tôi nhìn vào Scala, thấy những đặc điểm như Function1, và đang chơi xung quanh với các định nghĩa hàm như

def foo[T<:{def foo():Unit}](arg:T) = //something 
def bar(x:{def foo():Unit}) = //something 
def baz[T,V<:Function1[T,_]](x:T, y:V) = y(x) 

tôi nhìn vào bản thân mình và nghĩ rằng tại sao tôi không thể làm điều tương tự? Tại sao "baz" trả lại một cái gì? Nó không thể suy ra kiểu trả về thực tế tại thời gian biên dịch? Tại sao tôi phải khai báo kiểu trả về của "foo" nếu tôi thậm chí không thể sử dụng nó?

Tôi muốn để có thể làm

def biff[T,V:{def foo(x:T):Unit}] = //something 

hoặc

def boff[T<:{def foo(x:Double):_}](y:T) = y.foo _ 

Bạn có thể làm điều này và tôi chỉ còn thiếu một cái gì đó? Hoặc nếu không, tại sao không?

+0

Tôi không rõ ràng về ví dụ 'biff'. Có một đối số còn thiếu? –

+0

@Aaron Novstrup không thiếu đối số. Tôi nhận được một lỗi khi tôi tuyên bố nó như thế. Nói tôi không thể định nghĩa "V" sao cho nó phụ thuộc vào "T." – wheaties

Trả lời

11

Cập nhật:

Trên thực tế, bạn có thể làm tốt hơn nhiều, và loại inferencer sẽ giúp bạn:

def boff[T,R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _ 

Đối baz, kỹ thuật tương tự sẽ cải thiện suy luận kiểu:

def baz[T,R,V](x:T, y:V)(implicit e: V <:< (T => R)) = e(y).apply(x) 

scala> baz(1, (i: Int) => i+1) 
res0: Int = 2 

Bạn có thể làm tốt hơn bằng cách cà ri:

def baz[T,R](x: T)(f: T => R) = f(x) 

giải pháp đầu tiên:

Loại inferencer sẽ không cung cấp các loại T cho bạn, nhưng bạn có thể làm:

class Boff[T] { 
    def apply[R](y: T)(implicit e: T <:< {def foo(x: Double): R}) = e(y).foo _ 
} 
object boff { 
    def apply[T] = new Boff[T] 
} 
+0

+1 Đó là thông minh. –

2

Đối foo:

def foo[R,T<:{def foo():R}](arg:T) = ... 

Trong trường hợp baz, bạn nói rằng V phải là một hàm từ T đối với một số loại. Loại này không thể xuất hiện trong loại kết quả: bạn có thể viết như thế nào? Vì vậy, trình biên dịch chỉ có thể phỏng đoán rằng loại kết quả là Any. Nếu bạn cung cấp cho nó một cái tên, tuy nhiên, bạn sẽ có được

scala> def baz[T,R,V<:Function1[T,R]](x:T, y:V) = y(x) 
baz: [T,R,V <: (T) => R](x: T,y: V)R 
6

Sự khác biệt cơ bản giữa Scala và C++ là mỗi lớp trong Scala được biên dịch một lần, và sau đó trở thành có sẵn như là-là để sử dụng với bất cứ điều gì mà phụ thuộc vào nó , trong khi một lớp templated trong C++ phải được biên dịch cho mọi phụ thuộc mới.

Vì vậy, trên thực tế, mẫu C++ tạo ra các lớp được biên dịch N, trong khi Scala chỉ tạo một lớp.

Không thể suy ra loại trả lại thực tế tại thời gian biên dịch?

Vì nó phải được quyết định tại thời điểm lớp được biên dịch, có thể khác với thời gian sử dụng được biên dịch.

+0

Cảm ơn Daniel. Bạn luôn cung cấp "lý do" tuyệt vời. – wheaties

Các vấn đề liên quan