เรียก clojure จาก java


165

google hit อันดับต้น ๆ สำหรับ "การเรียก clojure จาก java" นั้นล้าสมัยและแนะนำให้ใช้clojure.lang.RTเพื่อคอมไพล์ซอร์สโค้ด คุณสามารถช่วยอธิบายอย่างชัดเจนเกี่ยวกับวิธีเรียก Clojure จาก Java โดยสมมติว่าคุณได้สร้าง jar จากโครงการ Clojure และรวมไว้ใน classpath ได้หรือไม่


8
ฉันไม่ทราบว่าการรวบรวมแหล่งที่มาในแต่ละครั้งนั้น "ล้าสมัย" เช่นนี้ มันเป็นการตัดสินใจออกแบบ ฉันกำลังทำอยู่ตอนนี้เพราะมันทำให้การบูรณาการรหัส Clojure เป็นมรดก Java Netbeans โครงการได้อย่างรวดเร็ว เพิ่ม Clojure เป็นห้องสมุดเพิ่มไฟล์ต้นฉบับ Clojure ตั้งค่าการโทรและการสนับสนุน Clojure ทันทีโดยไม่ต้องมีขั้นตอนการรวบรวม / การเชื่อมโยงหลายขั้นตอน! เสียเวลาเพียงเสี้ยววินาทีในการเริ่มต้นแต่ละแอป
Brian Knoblauch


2
ดูล่าสุดสำหรับ Clojure 1.8.0 - Clojure ตอนนี้มีการเชื่อมโยงคอมไพเลอร์โดยตรง
TWR Cole

คำตอบ:


167

อัปเดต : เนื่องจากคำตอบนี้ถูกโพสต์เครื่องมือบางอย่างที่มีการเปลี่ยนแปลง หลังจากคำตอบดั้งเดิมมีการอัปเดตรวมถึงข้อมูลเกี่ยวกับวิธีสร้างตัวอย่างด้วยเครื่องมือปัจจุบัน

มันไม่ง่ายเหมือนการคอมไพล์ไปที่ jar และเรียกเมธอดภายใน ดูเหมือนจะมีกลเม็ดเล็กน้อยที่จะทำให้ทุกอย่างทำงานได้ นี่คือตัวอย่างของไฟล์ Clojure ง่ายๆที่สามารถคอมไพล์ลงใน jar ได้:

(ns com.domain.tiny
  (:gen-class
    :name com.domain.tiny
    :methods [#^{:static true} [binomial [int int] double]]))

(defn binomial
  "Calculate the binomial coefficient."
  [n k]
  (let [a (inc n)]
    (loop [b 1
           c 1]
      (if (> b k)
        c
        (recur (inc b) (* (/ (- a b) b) c))))))

(defn -binomial
  "A Java-callable wrapper around the 'binomial' function."
  [n k]
  (binomial n k))

(defn -main []
  (println (str "(binomial 5 3): " (binomial 5 3)))
  (println (str "(binomial 10042 111): " (binomial 10042 111)))
)

หากคุณเรียกใช้คุณควรเห็นสิ่งต่อไปนี้:

(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...

และนี่คือโปรแกรม Java ที่เรียกฟังก์ชั่นใน-binomialtiny.jar

import com.domain.tiny;

public class Main {

    public static void main(String[] args) {
        System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
        System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
    }
}

มันเป็นผลผลิต:

(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

ชิ้นแรกของเวทมนต์ใช้:methodsคำสำคัญในgen-classคำสั่ง ที่ดูเหมือนว่าจะต้องให้คุณเข้าถึงฟังก์ชั่น Clojure เช่นวิธีการคงที่ใน Java

สิ่งที่สองคือการสร้างฟังก์ชั่น wrapper ที่สามารถเรียกได้โดย Java โปรดสังเกตว่ารุ่นที่สอง-binomialมีเส้นประอยู่ด้านหน้า

และแน่นอนขวด Clojure นั้นจะต้องอยู่ในเส้นทางของชั้นเรียน ตัวอย่างนี้ใช้ jar Clojure-1.1.0

อัปเดต : คำตอบนี้ได้รับการทดสอบอีกครั้งโดยใช้เครื่องมือต่อไปนี้:

  • Clojure 1.5.1
  • Leiningen 2.1.3
  • JDK 1.7.0 อัพเดท 25

ส่วน Clojure

ขั้นแรกสร้างโครงการและโครงสร้างไดเรกทอรีที่เกี่ยวข้องโดยใช้ Leiningen:

C:\projects>lein new com.domain.tiny

ตอนนี้เปลี่ยนเป็นไดเรกทอรีโครงการ

C:\projects>cd com.domain.tiny

ในไดเรกทอรีโครงการให้เปิดproject.cljไฟล์และแก้ไขตามที่แสดงด้านล่าง

(defproject com.domain.tiny "0.1.0-SNAPSHOT"
  :description "An example of stand alone Clojure-Java interop"
  :url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
  :license {:name "Eclipse Public License"
  :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]]
  :aot :all
  :main com.domain.tiny)

ตอนนี้ตรวจสอบให้แน่ใจว่าการอ้างอิงทั้งหมด (Clojure) พร้อมใช้งาน

C:\projects\com.domain.tiny>lein deps

คุณอาจเห็นข้อความเกี่ยวกับการดาวน์โหลดโถ Clojure ณ จุดนี้

ตอนนี้แก้ไขไฟล์ Clojure C:\projects\com.domain.tiny\src\com\domain\tiny.cljเพื่อให้มีโปรแกรม Clojure ที่แสดงในคำตอบเดิม (ไฟล์นี้สร้างขึ้นเมื่อ Leiningen สร้างโครงการ)

เวทมนตร์ส่วนใหญ่ที่นี่อยู่ในการประกาศเนมสเปซ ระบบ:gen-classบอกให้สร้างคลาสที่com.domain.tinyมีชื่อด้วยวิธีการคงที่เดียวที่เรียกว่าbinomialฟังก์ชั่นรับอาร์กิวเมนต์จำนวนเต็มสองข้อและส่งกลับสองครั้ง มีสองฟังก์ชันที่มีชื่อคล้ายกันคือฟังก์ชันbinomialClojure แบบดั้งเดิมและ-binomialและ wrapper สามารถเข้าถึงได้จาก Java -binomialหมายเหตุยัติภังค์ในชื่อของฟังก์ชั่น คำนำหน้าเริ่มต้นคือเครื่องหมายขีดกลาง แต่สามารถเปลี่ยนเป็นอย่างอื่นได้หากต้องการ -mainฟังก์ชั่นเพียงแค่ทำให้คู่ของการโทรไปยังฟังก์ชั่นทวินามเพื่อให้มั่นใจว่าเราจะได้รับผลลัพธ์ที่ถูกต้อง เมื่อต้องการทำเช่นนั้นให้คอมไพล์คลาสและเรียกใช้โปรแกรม

C:\projects\com.domain.tiny>lein run

คุณควรเห็นผลลัพธ์ที่แสดงในคำตอบเดิม

ตอนนี้บรรจุไว้ในขวดและวางไว้ที่ใดที่หนึ่งที่สะดวก คัดลอกโถ Clojure ที่นั่นด้วย

C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib

C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
        1 file(s) copied.

C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
        1 file(s) copied.

ส่วนของ Java

Leiningen มีงานในตัวlein-javacซึ่งน่าจะสามารถช่วยในการคอมไพล์ Java น่าเสียดายที่ดูเหมือนว่าจะใช้งานไม่ได้ในเวอร์ชัน 2.1.3 ไม่พบ JDK ที่ติดตั้งและไม่พบที่เก็บ Maven เส้นทางที่ทั้งสองมีช่องว่างที่ฝังตัวในระบบของฉัน ฉันคิดว่านั่นเป็นปัญหา Java IDE ใด ๆ ก็สามารถจัดการกับการคอมไพล์และแพ็คเกจได้เช่นกัน แต่สำหรับโพสต์นี้เรากำลังจะไปโรงเรียนเก่าและทำมันที่บรรทัดคำสั่ง

ขั้นแรกให้สร้างไฟล์Main.javaพร้อมเนื้อหาที่แสดงในคำตอบดั้งเดิม

เพื่อรวบรวมส่วน java

javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java

ตอนนี้สร้างไฟล์ที่มีข้อมูล meta เพื่อเพิ่มลงใน jar ที่เราต้องการสร้าง ในManifest.txtเพิ่มข้อความต่อไปนี้

Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main

ตอนนี้บรรจุมันทั้งหมดลงในไฟล์ jar ขนาดใหญ่หนึ่งไฟล์รวมถึงโปรแกรม Clojure และ jar Clojure ของเรา

C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar

ในการรันโปรแกรม:

C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

เอาท์พุทจะเหมือนกับที่ผลิตโดย Clojure เพียงอย่างเดียว แต่ผลลัพธ์ที่ได้จะถูกแปลงเป็น Java double

ตามที่กล่าวไว้แล้ว Java IDE อาจดูแลข้อโต้แย้งการรวบรวมและบรรจุภัณฑ์ที่ยุ่งเหยิง


4
1. ฉันสามารถวางตัวอย่างของคุณบนclojuredocs.orgเป็นตัวอย่างสำหรับมาโคร "ns" ได้หรือไม่ 2. อะไรคือ # ^ ต่อหน้า ": วิธีการ [# ^ {: สถิตจริง} [ทวินาม [int int] สองเท่า]]" (ฉันเป็นมือใหม่)?
Belun

5
@Belun แน่นอนคุณสามารถใช้เป็นตัวอย่าง - ฉันภูมิใจ "# ^ {: static true}" แนบข้อมูลเมตาบางส่วนเข้ากับฟังก์ชันที่ระบุว่าทวินามเป็นฟังก์ชันคงที่ มันจำเป็นในกรณีนี้เพราะในฝั่ง Java เรากำลังเรียกใช้ฟังก์ชันจาก main - ฟังก์ชันคงที่ หากทวินามไม่คงที่การรวบรวมฟังก์ชั่นหลักในฝั่ง Java จะสร้างข้อผิดพลาดเกี่ยวกับ "วิธีการที่ไม่ใช่แบบคงที่ทวินาม (int, int) ไม่สามารถอ้างอิงจากบริบทแบบคงที่" มีตัวอย่างเพิ่มเติมในไซต์ Object Mentor
clartaq

4
มีสิ่งหนึ่งที่สำคัญที่ไม่ได้กล่าวถึงที่นี่ - ในการรวบรวมไฟล์ Clojure ไปยังคลาส Java คุณต้อง: (คอมไพล์ 'com.domain.tiny)
Domchi

คุณเป็นผู้รวบรวมแหล่ง Clojure อย่างไร นี่คือที่ฉันติดอยู่
Matthew Boston

@ MatthewBoston ตอนที่เขียนคำตอบฉันใช้ Enclojure ปลั๊กอินสำหรับ NetBeans IDE ตอนนี้ฉันอาจจะใช้ Leiningen แต่ยังไม่ได้ลองหรือทดสอบ
clartaq

119

ตั้งแต่ Clojure 1.6.0 มีวิธีใหม่ในการโหลดและเรียกใช้ฟังก์ชัน Clojure วิธีนี้เป็นวิธีที่นิยมใช้เรียก RT โดยตรง (และแทนที่คำตอบอื่น ๆ ที่นี่) Javadoc เป็นที่นี่ - clojure.java.api.Clojureจุดเริ่มต้นที่หลักคือ

ในการค้นหาและเรียกใช้ฟังก์ชัน Clojure:

IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);

ฟังก์ชั่นclojure.coreจะถูกโหลดโดยอัตโนมัติ สามารถโหลด namespaces อื่น ๆ ผ่านทาง

IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));

IFns สามารถส่งผ่านไปยังฟังก์ชันคำสั่งซื้อที่สูงขึ้นได้เช่นตัวอย่างด้านล่างส่งผ่านplusไปยังread:

IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));

ส่วนใหญ่IFnใน Clojure อ้างถึงฟังก์ชั่น อย่างไรก็ตามมีการอ้างอิงถึงค่าข้อมูลที่ไม่ใช่ฟังก์ชั่น หากต้องการเข้าถึงสิ่งเหล่านี้ให้ใช้derefแทนfn:

IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);

บางครั้ง (หากใช้ส่วนอื่น ๆ ของรันไทม์ Clojure) คุณอาจต้องตรวจสอบให้แน่ใจว่าการเริ่มต้น Clojure นั้นถูกต้อง - การเรียกใช้วิธีการในคลาส Clojure นั้นเพียงพอสำหรับวัตถุประสงค์นี้ หากคุณไม่จำเป็นต้องเรียกใช้เมธอดบน Clojure เพียงแค่ทำให้คลาสการโหลดนั้นเพียงพอ (ในอดีตมีคำแนะนำที่คล้ายกันในการโหลดคลาส RT ซึ่งเป็นที่ต้องการตอนนี้):

Class.forName("clojure.java.api.Clojure") 

1
การใช้วิธีการนี้สคริปต์ไม่สามารถใช้อัญประกาศ '() และต้องการสิ่งต่าง ๆ ได้ มีวิธีแก้ปัญหาสำหรับสิ่งนั้นหรือไม่?
Renato

2
ฉันคิดว่ามีเพียงรูปแบบพิเศษสองสามอย่างที่ไม่มีอยู่ในรูปแบบ vars Clojure.read("'(1 2 3")หนึ่งวิธีแก้ปัญหาคือการเข้าถึงได้ผ่านทาง มันจะมีเหตุผลที่จะยื่นเรื่องนี้เป็นคำขอการปรับปรุงแม้ว่าจะให้ Clojure.quote () หรือโดยการทำให้มันทำงานเป็น var
Alex Miller

1
@ Renato ไม่จำเป็นต้องพูดอะไรเลยเพราะไม่มีอะไรที่ถูกประเมินโดยกฎการประเมินของ Clojure อยู่ดี หากคุณต้องการรายการที่มีตัวเลข 1-3 แล้วแทนที่จะเขียน'(1 2 3)ว่าคุณเขียนอะไรทำนองClojure.var("clojure.core", "list").invoke(1,2,3)นี้ และคำตอบนั้นมีตัวอย่างของวิธีใช้อยู่แล้วrequire: มันเป็นแค่รูปแบบอื่น ๆ
amalloy

34

แก้ไขคำตอบนี้ถูกเขียนขึ้นในปี 2010 และทำงานในเวลานั้น ดูคำตอบของ Alex Miller สำหรับวิธีการที่ทันสมัยกว่า

รหัสประเภทใดที่โทรมาจาก Java? หากคุณมีคลาสที่สร้างด้วยคลาส gen ให้เรียกมันว่าคลาส หากคุณต้องการเรียกใช้ฟังก์ชันจากสคริปต์ให้ดูตัวอย่างต่อไปนี้ตัวอย่างต่อไปนี้

หากคุณต้องการประเมินโค้ดจากสตริงภายใน Java คุณสามารถใช้รหัสต่อไปนี้:

import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.StringReader;

public class Foo {
  public static void main(String[] args) throws Exception {
    // Load the Clojure script -- as a side effect this initializes the runtime.
    String str = "(ns user) (defn foo [a b]   (str a \" \" b))";

    //RT.loadResourceScript("foo.clj");
    Compiler.load(new StringReader(str));

    // Get a reference to the foo function.
    Var foo = RT.var("user", "foo");

    // Call it!
    Object result = foo.invoke("Hi", "there");
    System.out.println(result);
  }
}

1
เพื่อขยายนิด ๆ หน่อย ๆ ถ้าคุณต้องการที่จะเข้าถึง var def'd ใน namespace (เช่น (def ของฉัน-var 10)) RT.var("namespace", "my-var").deref()ใช้นี้
Ivan Koblik

มันไม่ทำงานสำหรับฉันหากไม่เพิ่มRT.load("clojure/core");ที่จุดเริ่มต้น พฤติกรรมแปลก ๆ
hsestupin

ใช้งานได้และคล้ายกับสิ่งที่ฉันใช้ ไม่แน่ใจว่าเป็นเทคนิคใหม่ล่าสุดหรือไม่ ฉันอาจใช้ Clojure 1.4 หรือ 1.6 ไม่แน่ใจ
Yan King Yin

12

แก้ไข:ฉันเขียนคำตอบนี้เกือบสามปีที่ผ่านมา ใน Clojure 1.6 มี API ที่เหมาะสมสำหรับการโทร Clojure จาก Java โปรดตอบคำตอบของ Alex Millerสำหรับข้อมูลล่าสุด

คำตอบเดิมจาก 2011:

อย่างที่ฉันเห็นวิธีที่ง่ายที่สุด (ถ้าคุณไม่สร้างคลาสที่มีการคอมไพล์ AOT) คือการใช้ clojure.lang.RT เพื่อเข้าถึงฟังก์ชั่นใน clojure ด้วยคุณสามารถเลียนแบบสิ่งที่คุณจะทำใน Clojure (ไม่จำเป็นต้องรวบรวมสิ่งต่าง ๆ ในรูปแบบพิเศษ):

;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)

และใน Java:

// Example usage of the "bar-fn" function from the "foo.ns" namespace from Java
import clojure.lang.RT;
import clojure.lang.Symbol;
...
RT.var("clojure.core", "require").invoke(Symbol.intern("foo.ns"));
RT.var("foo.ns", "bar-fn").invoke(1, 2, 3);

มันค่อนข้าง verbose ใน Java แต่ฉันหวังว่ามันชัดเจนว่าชิ้นส่วนของรหัสเทียบเท่า

สิ่งนี้จะทำงานได้ตราบใดที่ Clojure และไฟล์ต้นฉบับ (หรือไฟล์ที่คอมไพล์) ของโค้ด Clojure ของคุณอยู่ใน classpath


1
คำแนะนำนี้ล้าสมัยตั้งแต่ Clojure 1.6 - โปรดใช้ clojure.java.api.Clojure แทน
Alex Miller

ไม่ใช่คำตอบที่ไม่ดีในตอนนั้น แต่ฉันตั้งใจจะให้รางวัลstackoverflow.com/a/23555959/1756702เป็นคำตอบที่เชื่อถือได้สำหรับ Clojure 1.6 จะลองอีกครั้งในวันพรุ่งนี้ ...
A. Webb

คำตอบของอเล็กซ์สมควรได้รับความโปรดปรานอย่างแน่นอน! โปรดแจ้งให้เราทราบหากฉันสามารถช่วยในการโอนเงินรางวัลถ้าจำเป็น
raek

@raek ฉันไม่รังเกียจที่คุณจะได้รับโบนัสเล็กน้อยจากนิ้วชี้ทริกที่มีคาเฟอีนเกิน หวังว่าจะได้พบคุณรอบ ๆ แท็ก Clojure อีกครั้ง
A. Webb

10

ฉันเห็นด้วยกับคำตอบของ clartaq แต่ฉันรู้สึกว่าผู้เริ่มต้นสามารถใช้:

  • ข้อมูลทีละขั้นตอนเกี่ยวกับวิธีการทำงานนี้จริง
  • ข้อมูลที่เป็นปัจจุบันสำหรับ Clojure 1.3 และ leiningen รุ่นล่าสุด
  • โถ Clojure ที่มีฟังก์ชั่นหลักดังนั้นจึงสามารถเรียกใช้แบบสแตนด์อโลนหรือเชื่อมโยงเป็นห้องสมุด

ดังนั้นฉันจึงครอบคลุมทั้งหมดในโพสต์บล็อกนี้

รหัส Clojure มีลักษณะเช่นนี้:

(ns ThingOne.core
 (:gen-class
    :methods [#^{:static true} [foo [int] void]]))

(defn -foo [i] (println "Hello from Clojure. My input was " i))

(defn -main [] (println "Hello from Clojure -main." ))

การตั้งค่าโครงการ leiningen 1.7.1 มีลักษณะดังนี้:

(defproject ThingOne "1.0.0-SNAPSHOT"
  :description "Hello, Clojure"
  :dependencies [[org.clojure/clojure "1.3.0"]]
  :aot [ThingOne.core]
  :main ThingOne.core)

รหัส Java มีลักษณะดังนี้:

import ThingOne.*;

class HelloJava {
    public static void main(String[] args) {
        System.out.println("Hello from Java!");
        core.foo (12345);
    }
}

หรือคุณยังสามารถได้รับรหัสทั้งหมดจากโครงการนี้บน GitHub


ทำไมคุณถึงใช้ AOT ไม่ทำให้โปรแกรมไม่เป็นอิสระต่อแพลตฟอร์มอีกต่อไปหรือ
Edward

3

ใช้งานได้กับ Clojure 1.5.0:

public class CljTest {
    public static Object evalClj(String a) {
        return clojure.lang.Compiler.load(new java.io.StringReader(a));
    }

    public static void main(String[] args) {
        new clojure.lang.RT(); // needed since 1.5.0        
        System.out.println(evalClj("(+ 1 2)"));
    }
}

2

หากกรณีใช้คือการรวม JAR ที่สร้างด้วย Clojure ในแอปพลิเคชัน Java ฉันพบว่ามีเนมสเปซแยกต่างหากสำหรับอินเทอร์เฟซระหว่างโลกทั้งสองให้เป็นประโยชน์:

(ns example-app.interop
  (:require [example-app.core :as core])

;; This example covers two-way communication: the Clojure library 
;; relies on the wrapping Java app for some functionality (through
;; an interface that the Clojure library provides and the Java app
;; implements) and the Java app calls the Clojure library to perform 
;; work. The latter case is covered by a class provided by the Clojure lib.
;; 
;; This namespace should be AOT compiled.

;; The interface that the java app can implement
(gen-interface
  :name com.example.WeatherForecast
  :methods [[getTemperature [] Double]])

;; The class that the java app instantiates
(gen-class
  :name com.example.HighTemperatureMailer
  :state state
  :init init
  ;; Dependency injection - take an instance of the previously defined
  ;; interface as a constructor argument
  :constructors {[com.example.WeatherForecast] []}
  :methods [[sendMails [] void]])

(defn -init [weather-forecast]
  [[] {:weather-forecast weather-forecast}])

;; The actual work is done in the core namespace
(defn -sendMails
  [this]
  (core/send-mails (.state this)))

เนมสเปซหลักสามารถใช้อินสแตนซ์ที่ถูกฉีดเพื่อให้งานสำเร็จ:

(ns example-app.core)

(defn send-mails 
  [{:keys [weather-forecast]}]
  (let [temp (.getTemperature weather-forecast)] ...)) 

เพื่อวัตถุประสงค์ในการทดสอบอินเตอร์เฟสสามารถถูก stubbed:

(example-app.core/send-mails 
  (reify com.example.WeatherForecast (getTemperature [this] ...)))

0

เทคนิคอื่นที่ใช้งานได้กับภาษาอื่น ๆ ที่อยู่ด้านบนของ JVM ก็คือการประกาศอินเตอร์เฟสสำหรับฟังก์ชั่นที่คุณต้องการโทรแล้วใช้ฟังก์ชั่น 'พร็อกซี' เพื่อสร้างอินสแตนซ์ที่ใช้งานมัน


-1

นอกจากนี้คุณยังสามารถใช้การคอมไพล์ AOT เพื่อสร้างคลาสไฟล์ที่เป็นตัวแทนรหัส clojure ของคุณ อ่านเอกสารเกี่ยวกับการรวบรวม gen-class และเพื่อน ๆ ในเอกสาร Clojure API สำหรับรายละเอียดเกี่ยวกับวิธีการทำเช่นนี้ แต่ในสาระสำคัญคุณจะสร้างคลาสที่เรียกฟังก์ชัน clojure สำหรับการเรียกใช้แต่ละวิธี

อีกทางเลือกหนึ่งคือการใช้ฟังก์ชั่น defprotocol และ deftype ใหม่ซึ่งจะต้องมีการรวบรวม AOT แต่ให้ประสิทธิภาพที่ดีขึ้น ฉันยังไม่ทราบรายละเอียดเกี่ยวกับวิธีการทำเช่นนี้ แต่คำถามในรายชื่อผู้รับจดหมายอาจจะเป็นการหลอกลวง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.