如何使用密封类的所有子类来处理子类实例?

时间:2019-10-29 22:03:09

标签: kotlin

我正在尝试在实践中使用 Kotlin 中的新sealedSubclasses功能。我需要处理来自密封类的一些子类的实例,但是我以前不知道哪个子类是,所以正常的过程是尝试所有子类。

假设有20个或更多子类。

下面,我对其进行了很多简化以使其易于遵循。我只使用了2个具有标量内部类型的子类。在现实世界中可能是复杂的对象类型。

sealed class Person {
  abstract var name:String
     // ...
}

data class Doctor(      
  var license: String = "",   
    // ....
  override var name:String = ""
) : Person()

// ....
data class Fireman ( 
  var medals: Int=0, 
  // ....   
  override var name:String = ""
) : Person()

现在我需要克隆该结构:首先尝试:

var p:Person = Doctor("123","Louis")
var q:Person
  // ...
Person.copy  // it is forbidden

所以我需要做

var p:Person = Doctor("123","Louis")
var q:Person
when (p) {
is Doctor -> q = p.copy()   
   // ...
is Fireman -> q = p.copy()
}   

请注意,这是错误的代码,因为总是添加新的子类,因此必须在克隆过程中手动添加,重复子块。

所以我尝试使用sealedSubclasses,但是为了模拟前面的代码,我没有将子类与类型连接起来

for(令牌中的子类:: class.sealedSubclasses){       如果(ele :: class.simpleName as String == metadata.qualifiedName){             // ??????       }   }

我该怎么办?

3 个答案:

答案 0 :(得分:1)

解决问题的一种方法是创建自己的抽象sealed class Person { abstract val name: String } data class Doctor( override val name: String, val license: String, val extraProperty: Any ) : Person() data class Fireman( override var name: String, val medals: Int ) : Person() val p: Person = Doctor("123", "Louis", "extra") var q: Person = when (p) { is Doctor -> p.copy(name = "New name", license = "Other license", extraProperty = "extra2") is Fireman -> p.copy(name = "New Name", medals = 15) // And so on... } 方法的实现:

@IBAction func searchButtonTapped(_ sender: Any) {
        if searchBar.isHidden == true {
            searchBar.isHidden = false
            self.navigationItem.titleView = self.searchBar
            searchActive = true
        } else if searchBar.isHidden == false {
            searchBar.isHidden = true
            searchActive = false
            let label = UILabel()
            label.text = "My Title"
            label.textColor = .red
            self.navigationItem.titleView = label
        }
    }

此帖子https://stackoverflow.com/a/47624138/3542143中有人遇到了与您类似的问题

答案 1 :(得分:1)

如果愿意,您可以可以通过反思来实现,但是我认为test_list= [['Alabama', {'Baldwin County': 182265}], ['Alabama', {'Barbour County': 27457}], ['Arkansas', {'Newton County': 8330}], ['Arkansas', {'Perry County': 10445}], ['Arkansas', {'Phillips County': 21757}], ['California', {'Madera County': 150865}], ['California', {'Marin County': 252409}], ['Colorado', {'Adams County': 441603}], ['Colorado', {'Alamosa County': 15445}], ['Colorado', {'Arapahoe County': 572003}] ] 不会有用。大约(未试用):

test_list1= [['Alabama', {'Baldwin County': 182265, 'Barbour County': 27457}],
 ['Arkansas', {'Newton County': 8330, 'Perry County': 10445, 'Phillips County': 21757}],
 ['California', {'Madera County': 150865, 'Marin County': 252409}],
 ['Colorado', {'Adams County': 441603, 'Alamosa County': 15445, 'Arapahoe County': 572003}]
]

当然,通常存在反射不安全和性能方面的警告。

答案 2 :(得分:0)

我认为,如果您使用空参数来调用copy(),则可以使用泛型。 (在我的手机上,因此请原谅任何语法问题。)

class Person <out T: Person> {
    abstract var name: String
    abstract fun unchangedCopy(): T
}

data class Unemployed (
    override var name: String
): Person<Unemployed>() {
    override fun unchangedCopy() = copy()
}

var p:Person = Unemployed(“John”)
var q:Person = p.unchangedCopy()

这将迫使您在每个新的子类中覆盖unchangedCopy,所以没有什么可忘记的。