이번에는 연산자 오버로딩 사용법과 연산자 오버로딩 사용 시 주의사항에 대해 알려드리겠습니다. 다음은 실제 사례입니다.
최근에는 데이터 처리를 해야 하는데 Mat, Vector, Point 등 일부 데이터 구조를 사용자 정의해야 합니다. 덧셈, 뺄셈, 곱셈, 나눗셈 등 4가지 산술 연산을 반복적으로 정의해야 합니다. 코드가 그다지 직관적이지 않고 자바스크립트에는 연산이 없습니다. C++, C#과 같은 기능인 연산자 오버로딩이 정말 귀찮아서 번역 코드에 연산자 오버로딩을 자동으로 구현하여 "국가를 구하고 싶습니다"라는 구현 아이디어입니다. 실제로 매우 간단합니다. 즉, 인터프리터를 작성하고 코드를 컴파일하는 것입니다. 예:
S = A + B (B - C.fun())/2 + D
`S로 번역됨 = 교체(replace(A, '+', 교체(replace(B, ' ',(replace(B,'-',C.fun())))),'/',2),'+',D)`
replace 함수에서 우리는 다음의 해당 연산자 함수를 호출합니다. object, 교체 함수 코드는 다음과 같습니다.
/** * 转换方法 * @param a * @param op * @param b * @returns {*} * @private */ export function __replace__(a,op,b){ if(typeof(a) != 'object' && typeof(b) != 'object'){ return new Function('a','b','return a' + op + 'b')(a,b) } if(!Object.getPrototypeOf(a).isPrototypeOf(b) && Object.getPrototypeOf(b).isPrototypeOf(a)){ throw '不同类型的对象不能使用四则运算' } let target = null if (Object.getPrototypeOf(a).isPrototypeOf(b)) { target = new Function('return ' + b.__proto__.constructor.name)() } if (Object.getPrototypeOf(b).isPrototypeOf(a)) { target = new Function('return ' + a.__proto__.constructor.name)() } if (op == '+') { if (target.__add__ != undefined) { return target.__add__(a, b) }else { throw target.toString() +'\n未定义__add__方法' } }else if(op == '-') { if (target.__plus__ != undefined) { return target.__plus__(a, b) }else { throw target.toString() + '\n未定义__plus__方法' } }else if(op == '*') { if (target.__multiply__ != undefined) { return target.__multiply__(a, b) }else { throw target.toString() + '\n未定义__multiply__方法' } } else if (op == '/') { if (target.__pide__ != undefined) { return target.__pide__(a, b) }else { throw target.toString() + '\n未定义__pide__方法' } } else if (op == '%') { if (target.__mod__ != undefined) { return target.__mod__(a, b) }else { throw target.toString() + '\n未定义__mod__方法' } } else if(op == '.*') { if (target.__dot_multiply__ != undefined) { return target.__dot_multiply__(a, b) }else { throw target.toString() + '\n未定义__dot_multiply__方法' } } else if(op == './') { if (target.__dot_pide__ != undefined) { return target.__dot_pide__(a, b) }else { throw target.toString() + '\n未定义__dot_pide__方法' } } else if(op == '**') { if (target.__power__ != undefined) { return target.__power__(a, b) }else { throw target.toString() + '\n未定义__power__方法' } }else { throw op + '运算符无法识别' } }
교체 구현은 너무 많은 설명 없이 매우 간단합니다. 중요한 부분은 코드를 컴파일하는 방법입니다. 대학에서 데이터 구조를 공부할 때 네 가지 산술 연산을 구현하는 것이 이 번역의 기초이지만 약간의 차이가 있습니다. 프로세스를 간략하게 설명하세요.
1. 표현식을 분할하고 변수와 연산자를 추출하여 메타배열 A를 얻습니다.
2. 메타배열을 탐색합니다.
요소가 연산자 덧셈, 뺄셈, 곱셈 및 나눗셈인 경우 스택에서 이전 요소를 팝하고
replace(last, 연산자로 변환,
요소가 ')'인 경우 스택에서 요소를 팝하고 '('를 만날 때까지 연결한 다음 스택에 푸시합니다. 여기서 요소가 있는지 여부에 주의해야 합니다. '(' 앞에는 함수 호출 또는 교체가 있습니다. 함수 호출 또는 교체인 경우 계속해서 데이터를 앞으로 팝하고 교체 함수를 닫아야 합니다.
/** * 表达式转换工具方法 * @param code */ export function translate (code) { let data = [] let tmp_code = code.replace(/\s/g,'') let tmp = [] let vari = tmp_code.split(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g) let ops = tmp_code.match(/["]+[^"]*["]+|[']+[^']*[']+|\*\*|\+|-|\*|\/|\(|\)|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|\}|=|%|\.\/|\.\*|,/g) for (let i = 0,len = ops.length; i < len; i++) { if (vari[i] != '') { tmp.push(vari[i]) } if (ops[i] != '') { tmp.push(ops[i]) } } tmp.push(vari[ops.length]) for (let i = 0; i < tmp.length; i++){ let item = tmp[i] if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/.test(tmp[i])) { let top = data.pop() let trans = '__replace__(' + top + ',\'' + tmp[i] + '\',' data.push(trans) }else{ if (')' == tmp[i]) { let trans0 = tmp[i] let top0 = data.pop() while (top0 != '(') { trans0 = top0 + trans0 top0 = data.pop() } trans0 = top0 + trans0 let pre = data[data.length - 1] while(/[_\w]+[\.]?[_\w]+/.test(pre) && !/^__replace__\(/.test(pre) && pre != undefined) { pre = data.pop() trans0 = pre + trans0 pre = data[data.length - 1] } pre = data[data.length - 1] while(pre != undefined && /^__replace__\(/.test(pre)){ pre = data.pop() trans0 = pre + trans0 + ')' pre = data[data.length - 1] } data.push(trans0) }else { let pre = data[data.length - 1] let trans1 = tmp[i] while(pre != undefined && /^__replace__\(/.test(pre) && !/\*\*|\+|-|\*|\/|\(|\?|>[=]|<[=]|={2}|:|&{2}|\|{2}|\{|=|\}|%|\.\/|\.\*/.test(item) && !/^__replace__\(/.test(item)) { if(tmp[i + 1] == undefined){ pre = data.pop() trans1 = pre + trans1 + ')' break; }else{ pre = data.pop() trans1 = pre + trans1 + ')' pre = data[data.length - 1] } } data.push(trans1) } } } let result = '' data.forEach((value, key, own) => { result += value }) return result }
export default class OOkay { constructor () { let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(this)) protos.forEach((proto, key, own) => { if(proto != 'constructor'){ Object.defineProperty(this, proto, { value:new Function(translate_block(proto, this[proto].toString())).call(this) }) } }) } }
/** * 类代码块转换工具 * @param name * @param block * @returns {string} */ export function translate_block (name , block) { let codes = block.split('\n') let reg = new RegExp('^' + name + '$') console.log(reg.source) codes[0] = codes[0].replace(name,'function') for(let i = 1; i < codes.length; i++) { if (codes[i].indexOf('//') != -1) { codes[i] = codes[i].substring(0,codes[i].indexOf('//')) } if(/\*\*|\+|-|\*|\/|%|\.\/|\.\*/g.test(codes[i])){ if (codes[i].indexOf('return ') != -1) { let ret_index = codes[i].indexOf('return ') + 7 codes[i] = codes[i].substring(0,ret_index) + translate(codes[i].substring(ret_index)) }else { let eq_index = codes[i].indexOf('=') + 1 codes[i] = codes[i].substring(0,eq_index) + translate(codes[i].substring(eq_index)) } } } return 'return ' + codes.join('\n') }
/** * 非继承类的注入方法 * @param target */ static inject (target) { let protos = Object.getOwnPropertyNames(Object.getPrototypeOf(target)) protos.forEach((proto, key, own) => { if (proto != 'constructor') { Object.defineProperty(target, proto, { value:new Function(translate_block(proto, target[proto].toString())).call(target) }) } }) }
static __$__(fn) { if(!(fn instanceof Function)){ throw '参数错误' } (new Function(translate_block('function',fn.toString()))).call(window)() }
이 기사의 사례를 읽으신 후 방법을 마스터하셨다고 생각합니다. 자세한 내용은 PHP 중국어 웹사이트의 다른 관련 기사를 주목하세요!
추천 읽기:
위 내용은 연산자 오버로딩을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!