面向对象

Z1h 语言支持面向对象, 并且支持多继承

声明

声明一个类有两种语言风格:

// map风格
class People {
	name: 'zwr',
	hi: e => print(`Hello, i am ${this.name}, you are ${e}`),
}

// 表达式风格
class Student {
	name = 'zwr'
	hi = e => print(`Hello, i am ${this.name}, you are ${e}`)
	func bye(from) {
		print(`Goodbye from ${from} to ${this.name}`)
	}
}

请注意, 两种声明风格不能混用

初始化实例

以上文创建的两个类为例

// go风格
p = new(People)

// python风格
s = Student()

类变量

// 风格1
p.name = 'zq'

// 风格2
s['name'] = 'zq'

类函数

p.hi('tester')

构造函数

在声明类变量的时候, 声明init函数即创建构造函数, 并且在继承关系中, 构造函数会从父类开始被调用, 顺序遵循 MRO 链的顺序.

建议通过map作为构造函数的参数

class A {
	init = e => print(`通过参数${e}构造了一个A对象`)
}

class B (A) {
	init: e => print(`通过参数${e}构造了一个B对象`),
}

A(123)
new(B, 456)

勾子函数

可以通过声明 settergetter 函数来创建写/读的钩子, 在不需要经过勾子的地方, 需要改为调用 StoreLoad 函数

// setter使用函数示例
class People {
	age = 24
	setter = (k, v) => {
		if (k == 'age') {
			this.Store(k, this.age + v)
		} else {
			panic('No key named ' + k)
		}
	}
}

p = new(People)
p.age = 100
print(p.age) // 124
p.name = 'zwr' // will panic

// getter使用函数示例
class Student {
	age = 24
	getter = (k, v) => {
		if (k == 'age') {
			var [age, has] = this.Load(k)
			if (has) {
				return age + ' Years'
			} else {
				return 'No age'
			}
		} else {
			panic('Cannot take ' + k)
		}
	}
}

s = new(Student)
print(s.age)
del(s, 'age')
print(s.age)
print(s.name) // panic

请注意, Load函数有两个返回值, 一个是获取到的真实的值, 第二个是true/false, 表示是否存在这个key

如果直接在setter或getter内使用this.xxx, 大概率会导致死循环, 请注意用Store和Load替换

继承的情况下, 父类的setter和getter将不生效

继承

单继承

class People {
	name = 'zwr'
}
class Student (People) {}

print(Student().name)

多继承

class AAA {
	name = 'zwr'
}
class BBB {
	age = 26
}
class CCC(AAA, BBB) {
	hi = e => print(`My name is ${this.name}, age is ${this.age}`)
}

var c = CCC()
c.hi()

super

使用 this.super() 可以获取父类的引用, 以获取父类函数

class AAA {
	hi = e=>print('Hi, i am AAA')
}
class BBB(AAA) {
	hi = e=> {
		print('Hi, i am BBB')
		this.super().hi()
	}
}

var b = BBB()
b.hi()

MRO

在多继承时, 免不了会出现优先级的冲突问题

使用 Object.mro(sth) 可以获得对象的MRO

class D() {}
class E() {}
class F() {}
class B(D, E) {}
class C(D, F) {}
class A(B, C) {}

Object.mro(A).map(e => e.Type())

// 可以看到, A类的MRO链是 [A, B, C, D, E, F, Object]

判断继承关系

class AAA {}
class BBB(AAA) {}
class CCC() {}
class DDD(BBB, CCC) {}

Object.isInstanceOf(BBB(), AAA) // true
Object.isInstanceOf(CCC(), AAA) // false
Object.isInstanceOf(DDD(), AAA) // true

BBB().InstanceOf(AAA) // true
CCC().InstanceOf(AAA) // false
DDD().InstanceOf(AAA) // true

强类型的类或对象

类或对象调用 SetStronglyTyped 函数, 类变量将不可以被修改类型, 或添加类变量

class People {age: 0}
People.SetStronglyTyped()

p1 = new(People)
p1.age = 20 // ok
p1.age = 'zwr' // panic

class Student {name = 'zwr'}

s1 = Student()
s2 = Student()

s1.SetStronglyTyped()
s1.name = 123 // panic
s2.name = 123 // ok

如果一个类是强类型的, 那么其衍生出来的子类和对象, 也都会是强类型的

如果需要取消强类型限制, 可以调用SetStronglyTyped(false)

协程(线程)安全的类或对象

类或对象调用 SetThreadSafe 函数, 类或变量将保证协程(线程)安全

class People {age: 0}
People.SetThreadSafe()

p = new(People)
print('Step 1:', p.age)
p.Lock()
print('Step 2:', p.age) // block
// wait
p.Unlock() // will print

如果一个类是协程安全的, 那么其衍生出来的子类和对象, 也都会是协程安全的

如果需要取消协程安全, 可以调用SetThreadSafe(false)

对象包含Lock、Unlock、RLock、RUnlock方法, 分别用于限制读和写操作, 可以手动调用函数以测试