//***********swift学习之30--访问控制--***************************


// 1.访问控制可以限定 其他源文件或模块中代码 对你代码的访问级别。

// 2.访问控制基于 模块与源文件。

// a:模块 指的是以独立单元构建和发布的Framework或Application。在Swift 中的一个模块可以使用import关键字引入另外一个模块。

// b:源文件是单个源码文件,它通常属于一个模块,源文件可以包含多个类和函数 的定义。


// Swift 为代码中的实体提供了三种不同的访问级别:public、internal、private。



// A: 函数类型访问权限

// 函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。

internal class SomeInternalClass {
    
}
private class SomePrivateClass {
    
}

// 下面的例子定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别。
//func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
//}

// 函数中其中一个类 SomeInternalClass 的访问级别是internal,另一个 SomePrivateClass 的访问级别是private。所以根据元组访问级别的原则,该元组的访问级别是private。
// 因为该函数返回类型的访问级别是private,所以你必须使用private修饰符,明确的声明该函数:

private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
    
    let intenalClass = SomeInternalClass()
    let privateClass = SomePrivateClass()

    return (intenalClass,privateClass)
}



// B: 枚举类型访问权限

// C:子类访问权限
// 子类的访问级别不得高于父类的访问级别。比如说,父类的访问级别是internal,子类的访问级别就不能申明为public。
public class FtheClass {
    internal func show() {
        print("超类")
    }
}

// 访问级别不能低于超类 internal > public
internal class SooClass: FtheClass  {
//    override internal func show() {
//        print("子类")
//    }
    
    override internal func show() {
        print("子类")
    }

}

let sup = FtheClass()
sup.show()

let subb = SooClass()
subb.show()



// D: 协议访问权限
// 如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。
// 如果你定义了一个public访问级别的 协议 ,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal。
public protocol TcpppProtocol {
    init(no1: Int)
}

public class MainnnClass {
    var no1: Int  // local storage
    init(no1: Int) {
        self.no1 = no1 // initialization
    }
}

class SubbbClass:  MainnnClass, TcpppProtocol {
    var no2: Int
    init(no1: Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    
    // Requires only one parameter for convenient method
    required override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}

let ressss = MainnnClass(no1: 20)
let showwwww = SubbbClass(no1: 30, no2: 50)

print("ressss is: \(ressss.no1)")
print("showwwww is: \(showwwww.no1)")
print("showwwww is: \(showwwww.no2)")





// E:泛型访问权限
// 泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。
public struct TTOS<T> {
    var items = [T]()
//    private mutating func push(item: T) {
//        items.append(item)
//    }
    
    public mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var tost = TTOS<String>()
tost.push(item: "Swift")
print(tost.items)

tost.push(item: "泛型")
print(tost.items)

tost.push(item: "类型参数")
print(tost.items)

tost.push(item: "类型参数名")
print(tost.items)
let deletetos = tost.pop()


// F: 类型别名
// 任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。
// 比如说,一个private级别的类型别名可以设定给一个public、internal、private的类型,但是一个public级别的类型别名只能设定给一个public级别的类型,不能设定给internal或private 级别的类型。
// 注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。


public protocol Containercc {
    associatedtype ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType {  get }
}

struct Stackkk<T>: Containercc {
    // original Stack<T> implementation
    var items = [T]()
    mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
    
    // conformance to the Container protocol
    mutating func append(item:  T) {
        self.push(item: item)
    }
    
    var count: Int {
        return items.count
    }
    
    subscript(i: Int) -> T {
        return items[i]
    }
}

func allItemsMatched<
    C1: Containercc, C2: Containercc>
    (someContainer: C1, anotherContainer: C2) -> Bool
    
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
    // check that both containers contain the same number of items
    if someContainer.count != anotherContainer.count {
        return false
    }
    
    // check each pair of items to see if they are equivalent
    for i in 0..<someContainer.count {
        if someContainer[i] != anotherContainer[i] {
            return false
        }
    }
    
    // all items match, so return true
    return true
}

var tosddd = Stackkk<String>()
tosddd.push(item: "Swift")
print(tosddd.items)

tosddd.push(item: "泛型")
print(tosddd.items)

tosddd.push(item: "Where 语句")
print(tosddd.items)


var tosff = Stackkk<String>()
tosff.push(item: "Swift")
print(tosff.items)

tosff.push(item: "泛型")
print(tosff.items)

tosff.push(item: "Where 语句")
print(tosff.items)

allItemsMatched(someContainer:tosddd,anotherContainer:tosff)