2017-06-09 29 views
6

Tôi có các hàm đại diện cho các bước trong quy trình. Mỗi chức năng cũng biết bước tiếp theo, nếu có. Tôi muốn để có thể làm điều gì đó như:Có thể tạo kiểu hàm đệ quy trong Kotlin không?

fun fooStep() : Step? { 
    ... do something ... 
    return ::barStep // the next step is barStep 
} 

Các chức năng này được gọi từ một chức năng điều phối Trung ương, trong đó có chứa mã một chút như thế này:

var step = startStep 
while (step != null) { 
    step = step() 
} 

Lưu ý rằng logic trong một bước cụ thể cũng xác định bước tiếp theo, nếu thậm chí có một bước.

Tôi nghĩ tôi có thể xác định Step như:

typealias Step =() -> Step? 

Vì vậy, một Step là một hàm trả về một Step, hoặc null. Tuy nhiên, điều này không thể biên dịch với:

Kotlin: Recursive type alias in expansion: Step 

Tôi có thể giải quyết vấn đề này bằng cách gói chức năng vào đối tượng. ví dụ:

data class StepWrapper(val step:() -> StepWrapper?) 

và thay đổi chữ ký chức năng của tôi cho phù hợp.

Thật không may, điều này có nghĩa rằng tôi không thể chỉ cần sử dụng literals chức năng (ví dụ: ::barStep), nhưng thay vì phải bọc chúng trong một StepWrapper:

fun fooStep() : StepWrapper? { 
    ... do something ... 
    return StepWrapper(::barStep) 
} 

(Tôi cũng phải thay đổi vòng lặp văn của tôi, cho phù hợp.)

Tôi muốn tránh sự cần thiết phải tạo các đối tượng bao bọc này, nếu có thể. Có cách nào để làm điều này trong Kotlin?

+1

https://github.com/Kotlin/KEEP/blob/master/proposals/type-aliases.md Không theo này, ít nhất là không sử dụng một typealias – Novaterata

+0

Có một lý do thuyết phục rằng một hàm Bước cần biết bước tiếp theo? Một cách tiếp cận khác là có một hàm Step trả về một Điều kiện, kết hợp với một đồ thị của các tham chiếu hàm Step. Mỗi nút trong biểu đồ chứa hàm bước được gọi và sau đó là Bản đồ <Điều kiện, Bước> của những gì cần gọi tiếp theo tùy thuộc vào Điều kiện được trả về. Sau đó sẽ có một người thi hành có thể đi qua biểu đồ này. – roobyroo

+0

@roobyroo Lợi ích của phương pháp 'Bản đồ <Điều kiện, Bước>' đối với phương pháp 'StepWrapper' được mô tả trong câu hỏi là gì? –

Trả lời

1

Bạn có thể xác định nó bằng cách sử dụng một số giao diện chung:

interface StepW<out T> :()->T? 

interface Step : StepW<Step> 


class Step1 : Step { 
    override fun invoke(): Step? = Step2() 
} 

class Step2 : Step { 
    override fun invoke(): Step? = null 
} 

đâu Step là loại hàm đệ quy của bạn.

+0

Thú vị! Tôi không biết rằng Kotlin sẽ cho phép bạn mở rộng một loại chức năng với một giao diện. Điều này ít nhất là giải quyết vấn đề đối tượng bao bọc, mặc dù nó quá xấu mà một lớp là cần thiết để thực sự thực hiện giao diện này. –

0

Đây là cách bạn có thể làm cho nó hoạt động mặc dù tôi thực sự không chắc chắn những gì bạn đang cố gắng để đạt được với nó:

typealias Fun<T> =() -> T 
typealias Step<T> =() -> (T) 

typealias Step1 = Step<Fun<Step2>> 
typealias Step2 = Step<Fun<Step3>> 
typealias Step3 = Step<Unit> 

fun step1(): Step1 { 
    return { 
     println("step 1") 
     ::step2 
    } 
} 

fun step2(): Step2 { 
    return { 
     println("step 2") 
     ::step3 
    } 
} 

fun step3(): Step3 { 
    return { println("done") } 
} 
+0

Điều này sẽ không hoạt động, vì tôi cần tất cả các bước để có cùng loại. Ngoài ra, một bước nhất định không phải lúc nào cũng có cùng một bước sau, hoặc cùng một số bước tiếp theo (tùy thuộc vào đầu vào), nhưng cách tiếp cận này mã hóa toàn bộ chiều dài của quy trình trong loại. –

0

Sử dụng một Enum để thực hiện các mô hình nhà nước với các quốc gia hữu hạn và thích trả về các giá trị không null. Một enum có thể kế thừa từ một hàm.

enum class Step :() -> Step { 
    Step1 { 
     override fun invoke() = Step2 
    }, 
    Step2 { 
     override fun invoke() = End 
    }, 
    End { 
     override fun invoke() = this 
    } 
} 

fun work() { 
    var step = Step.Step1 
    while (step !== Step.End) { 
     step = step() 
    } 
} 
Các vấn đề liên quan