簡體   English   中英

Swift中的遞歸枚舉

[英]Recursive Enumerations in Swift

我正在學習Swift 2(和C,但也不會很久),並且我已經達到了一個讓我在遞歸枚舉中掙扎很多的地方。

如果它是遞歸的,我似乎需要在enum之前放置indirect 然后我有第一個在括號之間有Int情況,因為稍后在switch中它返回一個Integer ,是嗎?

現在是第二個案例Addition的第一個問題。 我必須在括號之間放置ArithmeticExpression 我嘗試將Int放在那里,但它給了我一個錯誤,必須是ArithmeticExpression而不是Int 我的問題是為什么? 我無法想象這是什么。 為什么我不能把兩個Int放在那里?

下一個問題是關於ArithmeticExpression問題。 func solution它是一個名為expression的值,它是ArithmeticExpression類型,是正確的嗎? 其余的至少目前是完全清楚的。 如果有人能夠以一種簡單的方式向我解釋,那就太好了。

這是完整的代碼:

indirect enum ArithmeticExpression {
    case Number(Int)
    case Addition(ArithmeticExpression, ArithmeticExpression)
}

func solution(expression: ArithmeticExpression) -> Int {
    switch expression {
    case .Number(let value1):
        return value1;
    case . Addition(let value1, let value2):
        return solution(value1)+solution(value2);
    }
}

var ten = ArithmeticExpression.Number(10);
var twenty = ArithmeticExpression.Number(20);
var sum = ArithmeticExpression.Addition(ten, twenty);
var endSolution = solution(sum);
print(endSolution);

Addition案例采用兩個ArithmeticExpression而不是兩個Int的原因是它可以處理這樣的遞歸情況:

ArithmeticExpression.Addition(ArithmeticExpression.Addition(ArithmeticExpression.Number(1), ArithmeticExpression.Number(2)), ArithmeticExpression.Number(3))

或者,不止一行:

let addition1 = ArithmeticExpression.Addition(ArithmeticExpression.Number(1), ArithmeticExpression.Number(2))
let addition2 = ArithmeticExpression.Addition(addition1, ArithmeticExpression.Number(3))

代表:

(1 + 2) + 3

遞歸定義允許您不僅添加數字,還允許添加其他算術表達式。 這就是這個enum的力量所在:它可以表達多個嵌套的加法運算。

PeterPan,我有時認為過於現實的例子比幫助更令人困惑,因為在試圖理解示例代碼時很容易陷入困境。

遞歸枚舉只是一個枚舉,其關聯值是枚舉自身類型的情況。 而已。 只是一個包含案例的枚舉,可以設置為與枚舉相同類型的關聯值。 #結束

為什么這是個問題? 為什么關鍵詞“間接”而不是說“遞歸”? 為什么需要任何關鍵字?

枚舉被“假定”按值復制,這​​意味着它們應該具有可預測大小的大小寫相關的值 - 由具有基本類型(如整數等)的大小寫組成。 然后,編譯器可以通過可以實例化的原始或關聯值的類型來猜測常規枚舉的最大可能大小。 畢竟你得到的枚舉只有一個選擇的案例 - 所以無論什么是案例中相關價值類型的最大選擇,這是枚舉類型在初始化時可以獲得的最大尺寸。 然后,編譯器可以在堆棧上留出大量內存,並且知道該枚舉實例的任何初始化或重新分配永遠不會大於該大小。 如果用戶將枚舉設置為具有小尺寸關聯值的情況,則可以,並且如果用戶將其設置為具有最大關聯值類型的情況。

但是,只要您定義一個具有不同大小相關類型的案例混合的枚舉,包括也是相同類型枚舉的值(因此可以使用任何枚舉案例進行初始化),就無法猜測枚舉實例的最大大小。 用戶可以使用允許與枚舉相同類型的關聯值的情況進行初始化 - 自身也使用同樣類型的情況初始化,依此類推:無限遞歸或可能性樹。 指向枚舉的枚舉的遞歸將繼續,直到枚舉初始化為具有“簡單”類型的相關值而不指向另一個枚舉。 想想一個簡單的Integer類型,它將“終止”枚舉鏈。

因此編譯器無法為此類枚舉在堆棧上留出正確大小的內存塊。 相反,它將案例關聯值作為POINTERS處理到存儲關聯值的堆內存。 這個枚舉本身可以指向另一個枚舉,依此類推。 這就是關鍵字是“間接”的原因 - 關聯值是通過指針間接引用的,而不是直接通過值引用的。

它類似於將inout參數傳遞給函數 - 而不是將值復制到函數中的編譯器,它傳遞一個指針來引用堆內存中的原始對象。

所以這就是它的全部。 一個不容易達到其最大大小的枚舉,因為它可以使用相同類型的枚舉和不可預測長度的鏈中不可預測的大小進行初始化。

正如各種示例所示,這種枚舉的典型用法是,您希望在括號內構建具有嵌套計算的公式的值樹,或者在初始化時在一個枚舉中捕獲具有節點和分支的祖先樹。 編譯器通過使用指針引用枚舉的關聯值而不是堆棧上的固定內存塊來處理所有這些。

所以基本上 - 如果你能想到你的代碼中你想讓枚舉鏈指向彼此的情況,以及相關值的各種選項 - 那么你將使用並理解一個遞歸枚舉!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM