2016-09-20 57 views
1

如何创建一个通用类在那里我可以一个项目的获取大小(或计数),无论它是一个int,字符串,等等如何获取泛型类的大小(数量)?

class Node<T: Equatable> { 

    var item: T? = nil 
    var next: Node? = nil 

    init(item:T, node:Node?) { 
     self.item = item 
     self.next = node 
    } 

    var count:Int { <-------------- this is what I need to fix 
     return item.count 
    } 

} 

我想这样做,所以我可以比较的项目是这样的:

let one = Node<Int>(item:1, node:nil) 
let two = Node<Int>(item:2, node:nil) 

return one.count < two.count <--------- should return true 

let str1 = Node<String>(item:"moose", node:nil) 
let str2 = Node<String>(item:"cow", node:nil) 

return str1.count < str2.count <------- should return false 

更新 我运行到正常的比较的问题了。我得到错误,“二元运算符'=='不能应用于'Any'和'Any'类型的操作数。 (又名“协议<>”)”

func search(item:Any) -> Bool { 

    var current:Node? = self.head 
    var found = false 

    while current != nil && found != true { 
     if current?.item == item { <---------this is the error line 
      found = true 
     } else { 
      current = current?.next 
     } 
    } 

    return found 
} 

我试图实现自定义的‘==’操作,除了一个节点比较

func ==(lhs: Node, rhs: Node) -> Bool { 
    return lhs.count == rhs.count 
} 

func ==(lhs: Any, rhs: Any) -> Bool { 
    return lhs == rhs 
} 

回答

1

你只需要让你的Node类符合到Equatable和可比性,改变你的项目类型以任何?:

class Node: Equatable, Comparable { 

    var item: Any? = nil 
    var next: Node? = nil 

    init(item: Any?, node: Node?) { 
     self.item = item 
     self.next = node 
    } 
    var count: Int { 
     // the trick is here, just conditionally casting to Int or String and return its Int value or the string characters count. 
     if let val = item as? Int { 
      return val 
     } 
     if let str = item as? String { 
      return str.characters.count 
     } 
     return 0 
    } 
} 

func ==(lhs: Node, rhs: Node) -> Bool { 
    return lhs.count == rhs.count 
} 

func <(lhs: Node, rhs: Node) -> Bool { 
    return lhs.count < rhs.count 
} 

用法:

let nodeOne = Node(item:1, node:nil) 
let nodeTwo = Node(item:2, node:nil) 

print(nodeOne < nodeTwo) // true 

let nodeStr1 = Node(item:"moose", node:nil) 
let nodeStr2 = Node(item:"cow", node:nil) 

print(nodeStr1 < nodeStr2) // false 
+0

这是一个很好的答案,虽然我遇到了一个问题。我在我的程序的其他地方以传统方式使用'=='运算符,并且不断收到错误:“二元运算符'=='不能应用于'Any'和'Any'类型的操作数。 (aka'protocol <>')。 – user3353890

+0

例如,在某些情况下,我尝试比较“if Node.item == item”...这就是我现在遇到的问题 – user3353890

+0

我不能帮助你进一步如果你不显示你的完整代码 –

1

我会建议简单地定义一个NodeItem的协议,需要一个_count财产和Comparable一致性,允许符合类型来实现自己的逻辑来定义他们希望如何节点的count是定义。

protocol NodeItem : Comparable { 
    // It's prefixed with an underscore to indicate that it shouldn't be used directly 
    // by anything other than Node (else it would be confusing for Int to have 
    // a count property) 
    var _count : Int { get } 
} 

// conform Int and String to NodeItem, allowing them to define _count 
extension String : NodeItem { 
    var _count: Int { return characters.count } 
} 

extension Int : NodeItem { 
    var _count: Int { return self } 
} 

然后,您可以限制你的Node类的项目类型与本协议,并通过简单地返回item_count实施count

class Node<Item : NodeItem> { 

    // I see no reason for item to be optional, as Node must be initialised with one. 
    var item: Item 
    var next: Node? 

    init(item: Item, next:Node?) { 
     self.item = item 
     self.next = next 
    } 

    var count: Int { 
     return item._count 
    } 
} 

let one = Node(item: 1, next: nil) 
let two = Node(item: 2, next: nil) 

print(one.count < two.count) // true 

let str1 = Node(item: "moose", next: nil) 
let str2 = Node(item: "cow", next: nil) 

print(str1.count < str2.count) // false 

的这样做的好处是itemNode的属性是强类型的,允许编译器强制执行类型安全性 - 例如防止构建,其中Item类型不实现其自己的_count逻辑或不是Comparable。另外,由于它不依赖于运行时类型转换,因此编译器将有更多的优化机会。

当涉及到执行搜索的逻辑,你可以简单地划上等号节点项目直接,因为他们是强类型。例如,一个LinkedList<Item>类:

class LinkedList<Item : NodeItem> { 

    let head : Node<Item> 

    init(head: Node<Item>) { 
     self.head = head 
    } 

    func search(item: Item) -> Bool { 

     var current : Node? = head 

     while current != nil { 
      if current?.item == item { 
       return true 
      } 
      current = current?.next 
     } 
     return false 
    } 
}